summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2013-10-31 15:06:23 -0500
committerDan Williams <dcbw@redhat.com>2013-10-31 15:25:38 -0500
commit8a173e1d7a1e3174027920b8bfb4be1bd37ffb34 (patch)
tree19023e1581afa86e2ca6275df9baaf398c0781ce
parentdf406d06b6d7e140a5f56c2eb2dff41517f77f22 (diff)
parentb3c0756f793f42eed95cc4fc183b189461c188c5 (diff)
downloadNetworkManager-8a173e1d7a1e3174027920b8bfb4be1bd37ffb34.tar.gz
core: removal of PendingActivation object from nm-manager.c (bgo #707335)
This branch decouples NMActiveConnection creation from device activation so that the NMActiveConnection object tracks the entire activation request (either internally-requested by the Policy or externally via D-Bus) from start to finish, instead of the previous situation where the PendingActivation handled D-Bus requests separately. This also will allow implementation of the DEACTIVATING state in the future. The NMActiveConnection object tracking the activation is not actually exported to D-Bus until the device or VPN activation is completely authorized and actually begins. It also encapsulates all the details needed to authorize a request into a new NMAuthSubject class, replacing various "dbus_sender" and "user_requested" arguments throughout the code.
-rw-r--r--src/Makefile.am2
-rw-r--r--src/devices/nm-device-infiniband.c7
-rw-r--r--src/devices/nm-device-modem.c5
-rw-r--r--src/devices/nm-device-olpc-mesh.c5
-rw-r--r--src/devices/nm-device-wifi.c5
-rw-r--r--src/devices/nm-device.c81
-rw-r--r--src/devices/wimax/Makefile.am1
-rw-r--r--src/nm-activation-request.c152
-rw-r--r--src/nm-activation-request.h11
-rw-r--r--src/nm-active-connection.c477
-rw-r--r--src/nm-active-connection.h42
-rw-r--r--src/nm-auth-subject.c210
-rw-r--r--src/nm-auth-subject.h68
-rw-r--r--src/nm-dbus-manager.c46
-rw-r--r--src/nm-dbus-manager.h6
-rw-r--r--src/nm-manager-auth.c113
-rw-r--r--src/nm-manager-auth.h20
-rw-r--r--src/nm-manager.c1390
-rw-r--r--src/nm-manager.h5
-rw-r--r--src/nm-policy.c164
-rw-r--r--src/settings/nm-agent-manager.c37
-rw-r--r--src/settings/nm-secret-agent.c67
-rw-r--r--src/settings/nm-secret-agent.h8
-rw-r--r--src/settings/nm-settings-connection.c195
-rw-r--r--src/settings/nm-settings.c108
-rw-r--r--src/vpn-manager/nm-vpn-connection.c92
-rw-r--r--src/vpn-manager/nm-vpn-connection.h5
-rw-r--r--src/vpn-manager/nm-vpn-manager.c71
-rw-r--r--src/vpn-manager/nm-vpn-manager.h10
-rw-r--r--src/vpn-manager/nm-vpn-service.c28
-rw-r--r--src/vpn-manager/nm-vpn-service.h10
31 files changed, 2097 insertions, 1344 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
index 3a64a8f7d9..bcac9ac300 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -248,6 +248,8 @@ nm_sources = \
nm-ip6-config.h \
nm-manager-auth.c \
nm-manager-auth.h \
+ nm-auth-subject.c \
+ nm-auth-subject.h \
nm-manager.c \
nm-manager.h \
nm-netlink-monitor.c \
diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c
index 4f71c7d7c3..b502fe70e2 100644
--- a/src/devices/nm-device-infiniband.c
+++ b/src/devices/nm-device-infiniband.c
@@ -147,6 +147,7 @@ get_generic_capabilities (NMDevice *dev)
static NMActStageReturn
act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{
+ NMActStageReturn ret;
NMActRequest *req;
NMConnection *connection;
NMSettingInfiniband *s_infiniband;
@@ -156,6 +157,10 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
+ ret = NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->act_stage1_prepare (dev, reason);
+ if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
+ return ret;
+
req = nm_device_get_act_request (dev);
g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
@@ -186,7 +191,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
return NM_ACT_STAGE_RETURN_FAILURE;
}
- return NM_DEVICE_CLASS (nm_device_infiniband_parent_class)->act_stage1_prepare (dev, reason);
+ return NM_ACT_STAGE_RETURN_SUCCESS;
}
static void
diff --git a/src/devices/nm-device-modem.c b/src/devices/nm-device-modem.c
index 6ca3c2b84c..0bed60cd80 100644
--- a/src/devices/nm-device-modem.c
+++ b/src/devices/nm-device-modem.c
@@ -252,8 +252,13 @@ deactivate (NMDevice *device)
static NMActStageReturn
act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
{
+ NMActStageReturn ret;
NMActRequest *req;
+ ret = NM_DEVICE_CLASS (nm_device_modem_parent_class)->act_stage1_prepare (device, reason);
+ if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
+ return ret;
+
req = nm_device_get_act_request (device);
g_assert (req);
diff --git a/src/devices/nm-device-olpc-mesh.c b/src/devices/nm-device-olpc-mesh.c
index 8a032e45f0..c419daa5e7 100644
--- a/src/devices/nm-device-olpc-mesh.c
+++ b/src/devices/nm-device-olpc-mesh.c
@@ -252,8 +252,13 @@ static NMActStageReturn
act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (dev);
+ NMActStageReturn ret;
gboolean scanning;
+ ret = NM_DEVICE_CLASS (nm_device_olpc_mesh_parent_class)->act_stage1_prepare (dev, reason);
+ if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
+ return ret;
+
/* disconnect companion device, if it is connected */
if (nm_device_get_act_request (NM_DEVICE (priv->companion))) {
nm_log_info (LOGD_OLPC_MESH, "(%s): disconnecting companion device %s",
diff --git a/src/devices/nm-device-wifi.c b/src/devices/nm-device-wifi.c
index 716ce9e3b3..e4c16613d9 100644
--- a/src/devices/nm-device-wifi.c
+++ b/src/devices/nm-device-wifi.c
@@ -2790,6 +2790,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
{
NMDeviceWifi *self = NM_DEVICE_WIFI (dev);
NMDeviceWifiPrivate *priv = NM_DEVICE_WIFI_GET_PRIVATE (self);
+ NMActStageReturn ret;
NMAccessPoint *ap = NULL;
NMActRequest *req;
NMConnection *connection;
@@ -2798,6 +2799,10 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
GSList *iter;
const char *mode;
+ ret = NM_DEVICE_CLASS (nm_device_wifi_parent_class)->act_stage1_prepare (dev, reason);
+ if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
+ return ret;
+
req = nm_device_get_act_request (NM_DEVICE (self));
g_return_val_if_fail (req != NULL, NM_ACT_STAGE_RETURN_FAILURE);
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 294aa9918f..660e26a59d 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -288,6 +288,7 @@ typedef struct {
/* master interface for bridge/bond/team slave */
NMDevice * master;
gboolean enslaved;
+ guint master_ready_id;
/* slave management */
gboolean is_master;
@@ -1935,10 +1936,61 @@ nm_device_ip_config_should_fail (NMDevice *self, gboolean ip6)
return FALSE;
}
+static void
+master_ready_cb (NMActiveConnection *active,
+ GParamSpec *pspec,
+ NMDevice *self)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ NMActiveConnection *master;
+
+ g_assert (priv->state == NM_DEVICE_STATE_PREPARE);
+
+ /* Notify a master device that it has a new slave */
+ g_assert (nm_active_connection_get_master_ready (active));
+ master = nm_active_connection_get_master (active);
+
+ priv->master = g_object_ref (nm_active_connection_get_device (master));
+ nm_device_master_add_slave (priv->master, self);
+
+ nm_log_dbg (LOGD_DEVICE, "(%s): master connection ready; master device %s",
+ nm_device_get_iface (self),
+ nm_device_get_iface (priv->master));
+
+ if (priv->master_ready_id) {
+ g_signal_handler_disconnect (active, priv->master_ready_id);
+ priv->master_ready_id = 0;
+ }
+
+ nm_device_activate_schedule_stage2_device_config (self);
+}
+
static NMActStageReturn
act_stage1_prepare (NMDevice *self, NMDeviceStateReason *reason)
{
- return NM_ACT_STAGE_RETURN_SUCCESS;
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
+ NMActiveConnection *active = NM_ACTIVE_CONNECTION (priv->act_request);
+
+ if (nm_active_connection_get_master (active)) {
+ /* If the master connection is ready for slaves, attach ourselves */
+ if (nm_active_connection_get_master_ready (active))
+ master_ready_cb (active, NULL, self);
+ else {
+ nm_log_dbg (LOGD_DEVICE, "(%s): waiting for master connection to become ready",
+ nm_device_get_iface (self));
+
+ /* Attach a signal handler and wait for the master connection to begin activating */
+ g_assert (priv->master_ready_id == 0);
+ priv->master_ready_id = g_signal_connect (active,
+ "notify::" NM_ACTIVE_CONNECTION_INT_MASTER_READY,
+ (GCallback) master_ready_cb,
+ self);
+ ret = NM_ACT_STAGE_RETURN_POSTPONE;
+ }
+ }
+
+ return ret;
}
/*
@@ -3445,7 +3497,8 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data)
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
const char *iface;
int ifindex;
- NMDevice *master;
+ NMActiveConnection *master;
+ NMDevice *master_device;
/* Clear the activation source ID now that this stage has run */
activation_source_clear (self, FALSE, 0);
@@ -3471,11 +3524,12 @@ nm_device_activate_stage3_ip_config_start (gpointer user_data)
*/
master = nm_active_connection_get_master (NM_ACTIVE_CONNECTION (priv->act_request));
if (master) {
- if (priv->enslaved == FALSE) {
+ master_device = nm_active_connection_get_device (master);
+ if (master_device && priv->enslaved == FALSE) {
nm_log_info (LOGD_DEVICE, "Activation (%s) connection '%s' waiting on master '%s'",
nm_device_get_iface (self),
nm_connection_get_id (nm_device_get_connection (self)),
- nm_device_get_iface (master));
+ nm_device_get_iface (master_device));
}
goto out;
}
@@ -4022,6 +4076,11 @@ clear_act_request (NMDevice *self)
nm_active_connection_set_default (NM_ACTIVE_CONNECTION (priv->act_request), FALSE);
+ if (priv->master_ready_id) {
+ g_signal_handler_disconnect (priv->act_request, priv->master_ready_id);
+ priv->master_ready_id = 0;
+ }
+
g_object_unref (priv->act_request);
priv->act_request = NULL;
}
@@ -4425,8 +4484,6 @@ nm_device_activate (NMDevice *self, NMActRequest *req)
nm_device_state_changed (self, NM_DEVICE_STATE_IP_CONFIG, NM_DEVICE_STATE_REASON_CONNECTION_ASSUMED);
nm_device_activate_schedule_stage3_ip_config_start (self);
} else {
- NMDevice *master;
-
/* HACK: update the state a bit early to avoid a race between the
* scheduled stage1 handler and nm_policy_device_change_check() thinking
* that the activation request isn't deferred because the deferred bit
@@ -4434,17 +4491,6 @@ nm_device_activate (NMDevice *self, NMActRequest *req)
*/
nm_device_state_changed (self, NM_DEVICE_STATE_PREPARE, NM_DEVICE_STATE_REASON_NONE);
- /* Handle any dependencies this connection might have */
- master = nm_active_connection_get_master (NM_ACTIVE_CONNECTION (req));
- if (master) {
- /* Master should at least already be activating */
- g_assert (nm_device_get_state (master) > NM_DEVICE_STATE_DISCONNECTED);
-
- g_assert (priv->master == NULL);
- priv->master = g_object_ref (master);
- nm_device_master_add_slave (master, self);
- }
-
nm_device_activate_schedule_stage1_device_prepare (self);
}
}
@@ -5027,6 +5073,7 @@ dispose (GObject *object)
dnsmasq_cleanup (self);
g_warn_if_fail (priv->slaves == NULL);
+ g_assert (priv->master_ready_id == 0);
/* Take the device itself down and clear its IPv4 configuration */
if (nm_device_get_managed (self) && deconfigure) {
diff --git a/src/devices/wimax/Makefile.am b/src/devices/wimax/Makefile.am
index 80a93b5be7..f6bd1e9e71 100644
--- a/src/devices/wimax/Makefile.am
+++ b/src/devices/wimax/Makefile.am
@@ -9,6 +9,7 @@ AM_CPPFLAGS = \
-I${top_builddir}/libnm-util \
-I${top_srcdir}/libnm-util \
$(DBUS_CFLAGS) \
+ $(POLKIT_CFLAGS) \
$(IWMX_SDK_CFLAGS) \
$(LIBNL_CFLAGS) \
$(GUDEV_CFLAGS)
diff --git a/src/nm-activation-request.c b/src/nm-activation-request.c
index 508b10db5d..18968f7633 100644
--- a/src/nm-activation-request.c
+++ b/src/nm-activation-request.c
@@ -51,10 +51,6 @@ typedef struct {
} ShareRule;
typedef struct {
- NMConnection *connection;
- NMDevice *device;
- guint device_state_id;
- char *dbus_sender;
GSList *secrets_calls;
gboolean shared;
GSList *share_rules;
@@ -70,14 +66,6 @@ nm_act_request_get_connection (NMActRequest *req)
return nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (req));
}
-const char *
-nm_act_request_get_dbus_sender (NMActRequest *req)
-{
- g_return_val_if_fail (NM_IS_ACT_REQUEST (req), NULL);
-
- return NM_ACT_REQUEST_GET_PRIVATE (req)->dbus_sender;
-}
-
/*******************************************************************/
typedef struct {
@@ -157,6 +145,7 @@ void
nm_act_request_cancel_secrets (NMActRequest *self, guint32 call_id)
{
NMActRequestPrivate *priv;
+ NMConnection *connection;
GSList *iter;
g_return_if_fail (self);
@@ -165,6 +154,7 @@ nm_act_request_cancel_secrets (NMActRequest *self, guint32 call_id)
priv = NM_ACT_REQUEST_GET_PRIVATE (self);
+ connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (self));
for (iter = priv->secrets_calls; iter; iter = g_slist_next (iter)) {
GetSecretsInfo *info = iter->data;
@@ -173,7 +163,7 @@ nm_act_request_cancel_secrets (NMActRequest *self, guint32 call_id)
priv->secrets_calls = g_slist_remove_link (priv->secrets_calls, iter);
g_slist_free (iter);
- nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection), call_id);
+ nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (connection), call_id);
g_free (info);
break;
}
@@ -295,13 +285,15 @@ nm_act_request_add_share_rule (NMActRequest *req,
/********************************************************************/
static void
-device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self)
+device_state_changed (NMActiveConnection *active,
+ NMDevice *device,
+ NMDeviceState new_state,
+ NMDeviceState old_state)
{
- NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (self);
NMActiveConnectionState ac_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
/* Set NMActiveConnection state based on the device's state */
- switch (nm_device_get_state (device)) {
+ switch (new_state) {
case NM_DEVICE_STATE_PREPARE:
case NM_DEVICE_STATE_CONFIG:
case NM_DEVICE_STATE_NEED_AUTH:
@@ -321,13 +313,6 @@ device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self)
case NM_DEVICE_STATE_UNMANAGED:
case NM_DEVICE_STATE_UNAVAILABLE:
ac_state = NM_ACTIVE_CONNECTION_STATE_DEACTIVATED;
-
- /* No longer need to pay attention to device state */
- if (priv->device && priv->device_state_id) {
- g_signal_handler_disconnect (priv->device, priv->device_state_id);
- priv->device_state_id = 0;
- }
- g_clear_object (&priv->device);
break;
default:
break;
@@ -335,11 +320,33 @@ device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self)
if ( ac_state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED
|| ac_state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) {
- nm_active_connection_set_default (NM_ACTIVE_CONNECTION (self), FALSE);
- nm_active_connection_set_default6 (NM_ACTIVE_CONNECTION (self), FALSE);
+ nm_active_connection_set_default (active, FALSE);
+ nm_active_connection_set_default6 (active, FALSE);
}
- nm_active_connection_set_state (NM_ACTIVE_CONNECTION (self), ac_state);
+ nm_active_connection_set_state (active, ac_state);
+}
+
+static void
+master_failed (NMActiveConnection *self)
+{
+ NMDevice *device;
+ NMDeviceState device_state;
+
+ /* If the connection has an active device, fail it */
+ device = nm_active_connection_get_device (self);
+ if (device) {
+ device_state = nm_device_get_state (device);
+ if (nm_device_is_activating (device) || (device_state == NM_DEVICE_STATE_ACTIVATED)) {
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_DEPENDENCY_FAILED);
+ return;
+ }
+ }
+
+ /* If no device, or the device wasn't active, just move to deactivated state */
+ nm_active_connection_set_state (self, NM_ACTIVE_CONNECTION_STATE_DEACTIVATED);
}
/********************************************************************/
@@ -350,48 +357,31 @@ device_state_changed (NMDevice *device, GParamSpec *pspec, NMActRequest *self)
* @connection: the connection to activate @device with
* @specific_object: the object path of the specific object (ie, WiFi access point,
* etc) that will be used to activate @connection and @device
- * @user_requested: pass %TRUE if the activation was requested via D-Bus,
- * otherwise %FALSE if requested internally by NM (ie, autoconnect)
- * @user_uid: if @user_requested is %TRUE, the Unix UID of the user that requested
- * @dbus_sender: if @user_requested is %TRUE, the D-BUS sender that requested
- * the activation
- * @device: the device/interface to configure according to @connection
- * @master: if the activation depends on another device (ie, bond or bridge
- * or team master to which this device will be enslaved) pass the #NMDevice
- * that this activation request be enslaved to
+ * @subject: the #NMAuthSubject representing the requestor of the activation
+ * @device: the device/interface to configure according to @connection; or %NULL
+ * if the connection describes a software device which will be created during
+ * connection activation
*
- * Begins activation of @device using the given @connection and other details.
+ * Creates a new device-based activation request.
*
* Returns: the new activation request on success, %NULL on error.
*/
NMActRequest *
nm_act_request_new (NMConnection *connection,
const char *specific_object,
- gboolean user_requested,
- gulong user_uid,
- const char *dbus_sender,
- NMDevice *device,
- NMDevice *master)
+ NMAuthSubject *subject,
+ NMDevice *device)
{
- GObject *object;
-
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
- g_return_val_if_fail (NM_DEVICE (device), NULL);
-
- object = g_object_new (NM_TYPE_ACT_REQUEST,
- NM_ACTIVE_CONNECTION_INT_CONNECTION, connection,
- NM_ACTIVE_CONNECTION_INT_DEVICE, device,
- NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object,
- NM_ACTIVE_CONNECTION_INT_USER_REQUESTED, user_requested,
- NM_ACTIVE_CONNECTION_INT_USER_UID, user_uid,
- NM_ACTIVE_CONNECTION_INT_MASTER, master,
- NULL);
- if (object) {
- nm_active_connection_export (NM_ACTIVE_CONNECTION (object));
- NM_ACT_REQUEST_GET_PRIVATE (object)->dbus_sender = g_strdup (dbus_sender);
- }
-
- return (NMActRequest *) object;
+ g_return_val_if_fail (!device || NM_IS_DEVICE (device), NULL);
+ g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL);
+
+ return (NMActRequest *) g_object_new (NM_TYPE_ACT_REQUEST,
+ NM_ACTIVE_CONNECTION_INT_CONNECTION, connection,
+ NM_ACTIVE_CONNECTION_INT_DEVICE, device,
+ NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object,
+ NM_ACTIVE_CONNECTION_INT_SUBJECT, subject,
+ NULL);
}
static void
@@ -400,38 +390,12 @@ nm_act_request_init (NMActRequest *req)
}
static void
-constructed (GObject *object)
-{
- NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object);
- NMConnection *connection;
- NMDevice *device;
-
- G_OBJECT_CLASS (nm_act_request_parent_class)->constructed (object);
-
- connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (object));
- priv->connection = g_object_ref (connection);
-
- device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object));
- if (device) {
- priv->device = g_object_ref (device);
- priv->device_state_id = g_signal_connect (priv->device,
- "notify::" NM_DEVICE_STATE,
- G_CALLBACK (device_state_changed),
- NM_ACT_REQUEST (object));
- }
-}
-
-static void
dispose (GObject *object)
{
NMActRequestPrivate *priv = NM_ACT_REQUEST_GET_PRIVATE (object);
+ NMConnection *connection;
GSList *iter;
- if (priv->device && priv->device_state_id) {
- g_signal_handler_disconnect (priv->device, priv->device_state_id);
- priv->device_state_id = 0;
- }
-
/* Clear any share rules */
if (priv->share_rules) {
nm_act_request_set_shared (NM_ACT_REQUEST (object), FALSE);
@@ -439,22 +403,16 @@ dispose (GObject *object)
}
/* Kill any in-progress secrets requests */
- for (iter = priv->secrets_calls; iter; iter = g_slist_next (iter)) {
+ connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (object));
+ for (iter = priv->secrets_calls; connection && iter; iter = g_slist_next (iter)) {
GetSecretsInfo *info = iter->data;
- g_assert (priv->connection);
- nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (priv->connection), info->call_id);
+ nm_settings_connection_cancel_secrets (NM_SETTINGS_CONNECTION (connection), info->call_id);
g_free (info);
}
g_slist_free (priv->secrets_calls);
priv->secrets_calls = NULL;
- g_free (priv->dbus_sender);
- priv->dbus_sender = NULL;
-
- g_clear_object (&priv->device);
- g_clear_object (&priv->connection);
-
G_OBJECT_CLASS (nm_act_request_parent_class)->dispose (object);
}
@@ -462,11 +420,13 @@ static void
nm_act_request_class_init (NMActRequestClass *req_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (req_class);
+ NMActiveConnectionClass *active_class = NM_ACTIVE_CONNECTION_CLASS (req_class);
g_type_class_add_private (req_class, sizeof (NMActRequestPrivate));
/* virtual methods */
- object_class->constructed = constructed;
object_class->dispose = dispose;
+ active_class->master_failed = master_failed;
+ active_class->device_state_changed = device_state_changed;
}
diff --git a/src/nm-activation-request.h b/src/nm-activation-request.h
index cd645ce9c2..87ea41f916 100644
--- a/src/nm-activation-request.h
+++ b/src/nm-activation-request.h
@@ -48,18 +48,11 @@ GType nm_act_request_get_type (void);
NMActRequest *nm_act_request_new (NMConnection *connection,
const char *specific_object,
- gboolean user_requested,
- gulong user_uid,
- const char *dbus_sender,
- NMDevice *device,
- NMDevice *master);
+ NMAuthSubject *subject,
+ NMDevice *device);
NMConnection *nm_act_request_get_connection (NMActRequest *req);
-gulong nm_act_request_get_user_uid (NMActRequest *req);
-
-const char *nm_act_request_get_dbus_sender (NMActRequest *req);
-
gboolean nm_act_request_get_shared (NMActRequest *req);
void nm_act_request_set_shared (NMActRequest *req, gboolean shared);
diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c
index 5adf248708..c2442d46ab 100644
--- a/src/nm-active-connection.c
+++ b/src/nm-active-connection.c
@@ -27,6 +27,8 @@
#include "nm-dbus-manager.h"
#include "nm-device.h"
#include "nm-settings-connection.h"
+#include "nm-manager-auth.h"
+#include "NetworkManagerUtils.h"
#include "nm-active-connection-glue.h"
@@ -42,15 +44,22 @@ typedef struct {
char *path;
char *specific_object;
NMDevice *device;
+ guint32 device_state_id;
gboolean is_default;
gboolean is_default6;
NMActiveConnectionState state;
gboolean vpn;
- gboolean user_requested;
- gulong user_uid;
- NMDevice *master;
+ NMAuthSubject *subject;
+ NMActiveConnection *master;
+ gboolean master_ready;
+
+ NMAuthChain *chain;
+ const char *wifi_shared_permission;
+ NMActiveConnectionAuthResultFunc result_func;
+ gpointer user_data1;
+ gpointer user_data2;
} NMActiveConnectionPrivate;
enum {
@@ -67,15 +76,35 @@ enum {
PROP_INT_CONNECTION,
PROP_INT_DEVICE,
- PROP_INT_USER_REQUESTED,
- PROP_INT_USER_UID,
+ PROP_INT_SUBJECT,
PROP_INT_MASTER,
+ PROP_INT_MASTER_READY,
LAST_PROP
};
+static void check_master_ready (NMActiveConnection *self);
+
/****************************************************************/
+static const char *
+state_to_string (NMActiveConnectionState state)
+{
+ switch (state) {
+ case NM_ACTIVE_CONNECTION_STATE_UNKNOWN:
+ return "unknown";
+ case NM_ACTIVE_CONNECTION_STATE_ACTIVATING:
+ return "activating";
+ case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
+ return "activated";
+ case NM_ACTIVE_CONNECTION_STATE_DEACTIVATING:
+ return "deactivating";
+ case NM_ACTIVE_CONNECTION_STATE_DEACTIVATED:
+ return "deactivated";
+ }
+ return "(none)";
+}
+
NMActiveConnectionState
nm_active_connection_get_state (NMActiveConnection *self)
{
@@ -100,6 +129,8 @@ nm_active_connection_set_state (NMActiveConnection *self,
priv->state = new_state;
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_STATE);
+ check_master_ready (self);
+
if ( new_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED
|| old_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (priv->connection),
@@ -107,8 +138,10 @@ nm_active_connection_set_state (NMActiveConnection *self,
}
if (priv->state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED) {
- /* Device is no longer relevant when deactivated */
- g_clear_object (&priv->device);
+ /* Device is no longer relevant when deactivated; emit property change
+ * notification so clients re-read the value, which will be NULL due to
+ * conditions in get_property().
+ */
g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_DEVICES);
}
}
@@ -127,6 +160,21 @@ nm_active_connection_get_connection (NMActiveConnection *self)
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->connection;
}
+void
+nm_active_connection_set_connection (NMActiveConnection *self,
+ NMConnection *connection)
+{
+ NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+
+ /* Can't change connection after the ActiveConnection is exported over D-Bus */
+ g_return_if_fail (priv->path == NULL);
+ g_return_if_fail (priv->connection == NULL || !NM_IS_SETTINGS_CONNECTION (priv->connection));
+
+ if (priv->connection)
+ g_object_unref (priv->connection);
+ priv->connection = g_object_ref (connection);
+}
+
const char *
nm_active_connection_get_path (NMActiveConnection *self)
{
@@ -145,6 +193,11 @@ nm_active_connection_set_specific_object (NMActiveConnection *self,
{
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+ /* Nothing that calls this function should be using paths from D-Bus,
+ * where NM uses "/" to mean NULL.
+ */
+ g_assert (g_strcmp0 (specific_object, "/") != 0);
+
if (g_strcmp0 (priv->specific_object, specific_object) == 0)
return;
@@ -205,24 +258,37 @@ nm_active_connection_export (NMActiveConnection *self)
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
static guint32 counter = 0;
+ g_assert (priv->device || priv->vpn);
+
priv->path = g_strdup_printf (NM_DBUS_PATH "/ActiveConnection/%d", counter++);
nm_dbus_manager_register_object (nm_dbus_manager_get (), priv->path, self);
}
+NMAuthSubject *
+nm_active_connection_get_subject (NMActiveConnection *self)
+{
+ g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
+
+ return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->subject;
+}
+
gboolean
nm_active_connection_get_user_requested (NMActiveConnection *self)
{
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
- return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->user_requested;
+ return !nm_auth_subject_get_internal (NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->subject);
}
gulong
nm_active_connection_get_user_uid (NMActiveConnection *self)
{
+ NMActiveConnectionPrivate *priv;
+
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), G_MAXULONG);
+ priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
- return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->user_uid;
+ return nm_auth_subject_get_uid (priv->subject);
}
NMDevice *
@@ -233,7 +299,73 @@ nm_active_connection_get_device (NMActiveConnection *self)
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->device;
}
-NMDevice *
+static void
+device_state_changed (NMDevice *device,
+ NMDeviceState new_state,
+ NMDeviceState old_state,
+ NMDeviceStateReason reason,
+ gpointer user_data)
+{
+ NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data);
+ NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+
+ if (old_state < NM_DEVICE_STATE_DISCONNECTED)
+ return;
+
+ if (old_state > NM_DEVICE_STATE_DISCONNECTED) {
+ /* Ignore disconnects if this ActiveConnection has not yet started
+ * activating. This is caused by activating a device when it's
+ * already activated, which causes a deactivating of the device before
+ * activating the new connection.
+ */
+ if (new_state == NM_DEVICE_STATE_DISCONNECTED &&
+ old_state > NM_DEVICE_STATE_DISCONNECTED &&
+ priv->state == NM_ACTIVE_CONNECTION_STATE_UNKNOWN) {
+ return;
+ }
+
+ /* If the device used to be active, but now is disconnected/failed, we
+ * no longer care about its state.
+ */
+ if (new_state <= NM_DEVICE_STATE_DISCONNECTED || new_state == NM_DEVICE_STATE_FAILED) {
+ g_signal_handler_disconnect (device, priv->device_state_id);
+ priv->device_state_id = 0;
+ }
+ }
+
+ /* Let subclasses handle the state change */
+ if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->device_state_changed)
+ NM_ACTIVE_CONNECTION_GET_CLASS (self)->device_state_changed (self, device, new_state, old_state);
+}
+
+gboolean
+nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device)
+{
+ NMActiveConnectionPrivate *priv;
+
+ g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
+ g_return_val_if_fail (!device || NM_IS_DEVICE (device), FALSE);
+
+ priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+
+ if (device) {
+ g_return_val_if_fail (priv->device == NULL, FALSE);
+
+ /* Device obviously can't be its own master */
+ g_return_val_if_fail (!priv->master || device != nm_active_connection_get_device (priv->master), FALSE);
+
+ priv->device = g_object_ref (device);
+ g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_DEVICE);
+
+ priv->device_state_id = g_signal_connect (device,
+ "state-changed",
+ G_CALLBACK (device_state_changed),
+ self);
+ }
+ return TRUE;
+}
+
+NMActiveConnection *
nm_active_connection_get_master (NMActiveConnection *self)
{
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), NULL);
@@ -241,6 +373,234 @@ nm_active_connection_get_master (NMActiveConnection *self)
return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->master;
}
+/**
+ * nm_active_connection_get_master_ready:
+ * @self: the #NMActiveConnection
+ *
+ * Returns: %TRUE if the connection has a master connection, and that
+ * master connection is ready to accept slaves. Otherwise %FALSE.
+ */
+gboolean
+nm_active_connection_get_master_ready (NMActiveConnection *self)
+{
+ g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (self), FALSE);
+
+ return NM_ACTIVE_CONNECTION_GET_PRIVATE (self)->master_ready;
+}
+
+static void
+check_master_ready (NMActiveConnection *self)
+{
+ NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+ NMActiveConnectionState master_state = NM_ACTIVE_CONNECTION_STATE_UNKNOWN;
+
+ if (priv->state != NM_ACTIVE_CONNECTION_STATE_ACTIVATING) {
+ nm_log_dbg (LOGD_DEVICE, "(%p): not signalling master-ready (not activating)", self);
+ return;
+ }
+ if (!priv->master) {
+ nm_log_dbg (LOGD_DEVICE, "(%p): not signalling master-ready (no master)", self);
+ return;
+ }
+ if (priv->master_ready) {
+ nm_log_dbg (LOGD_DEVICE, "(%p): not signalling master-ready (already signaled)", self);
+ return;
+ }
+
+ /* ActiveConnetions don't enter the ACTIVATING state until they have a
+ * NMDevice in PREPARE or higher states, so the master active connection's
+ * device will be ready to accept slaves when the master is in ACTIVATING
+ * or higher states.
+ */
+ master_state = nm_active_connection_get_state (priv->master);
+ nm_log_dbg (LOGD_DEVICE, "(%p): master ActiveConnection [%p] state now '%s' (%d)",
+ self, priv->master, state_to_string (master_state), master_state);
+
+ if ( master_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATING
+ || master_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) {
+ nm_log_dbg (LOGD_DEVICE, "(%p): signalling master-ready", self);
+
+ priv->master_ready = TRUE;
+ g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_INT_MASTER_READY);
+
+ /* Also notify clients to recheck the exported 'master' property to
+ * ensure that if the master connection was created without a device
+ * that we notify clients when the master device is known.
+ */
+ g_object_notify (G_OBJECT (self), NM_ACTIVE_CONNECTION_MASTER);
+ }
+}
+
+static void
+master_state_cb (NMActiveConnection *master,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data);
+ NMActiveConnectionState self_state = nm_active_connection_get_state (self);
+ NMActiveConnectionState master_state = nm_active_connection_get_state (master);
+
+ check_master_ready (self);
+
+ nm_log_dbg (LOGD_DEVICE, "(%p): master ActiveConnection [%p] state now '%s' (%d)",
+ self, master, state_to_string (master_state), master_state);
+
+ /* Master is deactivating, so this active connection must also deactivate */
+ if (self_state < NM_ACTIVE_CONNECTION_STATE_DEACTIVATING &&
+ master_state >= NM_ACTIVE_CONNECTION_STATE_DEACTIVATING) {
+ nm_log_dbg (LOGD_DEVICE, "(%p): master ActiveConnection [%p] '%s' failed",
+ self, master, nm_active_connection_get_name (master));
+
+ g_signal_handlers_disconnect_by_func (master,
+ (GCallback) master_state_cb,
+ self);
+ if (NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed)
+ NM_ACTIVE_CONNECTION_GET_CLASS (self)->master_failed (self);
+ }
+}
+
+/**
+ * nm_active_connection_set_master:
+ * @self: the #NMActiveConnection
+ * @master: if the activation depends on another device (ie, bond or bridge
+ * master to which this device will be enslaved) pass the #NMActiveConnection
+ * that this activation request is a child of
+ *
+ * Sets the master active connection of @self.
+ */
+void
+nm_active_connection_set_master (NMActiveConnection *self, NMActiveConnection *master)
+{
+ NMActiveConnectionPrivate *priv;
+
+ g_return_if_fail (NM_IS_ACTIVE_CONNECTION (self));
+ g_return_if_fail (NM_IS_ACTIVE_CONNECTION (master));
+
+ priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+
+ /* Master is write-once, and must be set before exporting the object */
+ g_return_if_fail (priv->master == NULL);
+ g_return_if_fail (priv->path == NULL);
+ if (priv->device) {
+ /* Note, the master ActiveConnection may not yet have a device */
+ g_return_if_fail (priv->device != nm_active_connection_get_device (master));
+ }
+
+ nm_log_dbg (LOGD_DEVICE, "(%p): master ActiveConnection is [%p] %s",
+ self, master, nm_active_connection_get_name (master));
+
+ priv->master = g_object_ref (master);
+ g_signal_connect (priv->master,
+ "notify::" NM_ACTIVE_CONNECTION_STATE,
+ (GCallback) master_state_cb,
+ self);
+
+ check_master_ready (self);
+}
+
+/****************************************************************/
+
+static void
+auth_done (NMAuthChain *chain,
+ GError *error,
+ DBusGMethodInvocation *unused,
+ gpointer user_data)
+{
+ NMActiveConnection *self = NM_ACTIVE_CONNECTION (user_data);
+ NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+ NMAuthCallResult result;
+
+ g_assert (priv->chain == chain);
+ g_assert (priv->result_func != NULL);
+
+ /* Must stay alive over the callback */
+ g_object_ref (self);
+
+ if (error) {
+ priv->result_func (self, FALSE, error->message, priv->user_data1, priv->user_data2);
+ goto done;
+ }
+
+ /* Caller has had a chance to obtain authorization, so we only need to
+ * check for 'yes' here.
+ */
+ result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL);
+ if (result != NM_AUTH_CALL_RESULT_YES) {
+ priv->result_func (self,
+ FALSE,
+ "Not authorized to control networking.",
+ priv->user_data1,
+ priv->user_data2);
+ goto done;
+ }
+
+ if (priv->wifi_shared_permission) {
+ result = nm_auth_chain_get_result (chain, priv->wifi_shared_permission);
+ if (result != NM_AUTH_CALL_RESULT_YES) {
+ priv->result_func (self,
+ FALSE,
+ "Not authorized to share connections via wifi.",
+ priv->user_data1,
+ priv->user_data2);
+ goto done;
+ }
+ }
+
+ /* Otherwise authorized and available to activate */
+ priv->result_func (self, TRUE, NULL, priv->user_data1, priv->user_data2);
+
+done:
+ nm_auth_chain_unref (chain);
+ priv->chain = NULL;
+ priv->result_func = NULL;
+ priv->user_data1 = NULL;
+ priv->user_data2 = NULL;
+
+ g_object_unref (self);
+}
+
+/**
+ * nm_active_connection_authorize:
+ * @self: the #NMActiveConnection
+ * @result_func: function to be called on success or error
+ * @user_data1: pointer passed to @result_func
+ * @user_data2: additional pointer passed to @result_func
+ *
+ * Checks whether the subject that initiated the active connection (read from
+ * the #NMActiveConnection::subject property) is authorized to complete this
+ * activation request.
+ */
+void
+nm_active_connection_authorize (NMActiveConnection *self,
+ NMActiveConnectionAuthResultFunc result_func,
+ gpointer user_data1,
+ gpointer user_data2)
+{
+ NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (self);
+ const char *wifi_permission = NULL;
+
+ g_return_if_fail (result_func != NULL);
+ g_return_if_fail (priv->chain == NULL);
+
+ priv->chain = nm_auth_chain_new_subject (priv->subject, NULL, auth_done, self);
+ g_assert (priv->chain);
+
+ /* Check that the subject is allowed to use networking at all */
+ nm_auth_chain_add_call (priv->chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
+
+ /* Shared wifi connections require special permissions too */
+ wifi_permission = nm_utils_get_shared_wifi_permission (priv->connection);
+ if (wifi_permission) {
+ priv->wifi_shared_permission = wifi_permission;
+ nm_auth_chain_add_call (priv->chain, wifi_permission, TRUE);
+ }
+
+ /* Wait for authorization */
+ priv->result_func = result_func;
+ priv->user_data1 = user_data1;
+ priv->user_data2 = user_data2;
+}
+
/****************************************************************/
static void
@@ -249,10 +609,18 @@ nm_active_connection_init (NMActiveConnection *self)
}
static void
+constructed (GObject *object)
+{
+ G_OBJECT_CLASS (nm_active_connection_parent_class)->constructed (object);
+ g_assert (NM_ACTIVE_CONNECTION_GET_PRIVATE (object)->subject);
+}
+
+static void
set_property (GObject *object, guint prop_id,
const GValue *value, GParamSpec *pspec)
{
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
+ const char *tmp;
switch (prop_id) {
case PROP_INT_CONNECTION:
@@ -260,25 +628,19 @@ set_property (GObject *object, guint prop_id,
priv->connection = g_value_dup_object (value);
break;
case PROP_INT_DEVICE:
- g_warn_if_fail (priv->device == NULL);
- priv->device = g_value_dup_object (value);
- if (priv->device)
- g_warn_if_fail (priv->device != priv->master);
+ nm_active_connection_set_device (NM_ACTIVE_CONNECTION (object), g_value_get_object (value));
break;
- case PROP_INT_USER_REQUESTED:
- priv->user_requested = g_value_get_boolean (value);
- break;
- case PROP_INT_USER_UID:
- priv->user_uid = g_value_get_ulong (value);
+ case PROP_INT_SUBJECT:
+ priv->subject = g_value_dup_object (value);
break;
case PROP_INT_MASTER:
- g_warn_if_fail (priv->master == NULL);
- priv->master = g_value_dup_object (value);
- if (priv->master)
- g_warn_if_fail (priv->master != priv->device);
+ nm_active_connection_set_master (NM_ACTIVE_CONNECTION (object), g_value_get_object (value));
break;
case PROP_SPECIFIC_OBJECT:
- priv->specific_object = g_value_dup_boxed (value);
+ tmp = g_value_get_boxed (value);
+ /* NM uses "/" to mean NULL */
+ if (g_strcmp0 (tmp, "/") != 0)
+ priv->specific_object = g_value_dup_boxed (value);
break;
case PROP_DEFAULT:
priv->is_default = g_value_get_boolean (value);
@@ -303,6 +665,7 @@ get_property (GObject *object, guint prop_id,
{
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
GPtrArray *devices;
+ NMDevice *master_device = NULL;
switch (prop_id) {
case PROP_CONNECTION:
@@ -316,7 +679,7 @@ get_property (GObject *object, guint prop_id,
break;
case PROP_DEVICES:
devices = g_ptr_array_sized_new (1);
- if (priv->device)
+ if (priv->device && priv->state < NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)
g_ptr_array_add (devices, g_strdup (nm_device_get_path (priv->device)));
g_value_take_boxed (value, devices);
break;
@@ -333,7 +696,15 @@ get_property (GObject *object, guint prop_id,
g_value_set_boolean (value, priv->vpn);
break;
case PROP_MASTER:
- g_value_set_boxed (value, priv->master ? nm_device_get_path (priv->master) : "/");
+ if (priv->master)
+ master_device = nm_active_connection_get_device (priv->master);
+ g_value_set_boxed (value, master_device ? nm_device_get_path (master_device) : "/");
+ break;
+ case PROP_INT_SUBJECT:
+ g_value_set_object (value, priv->subject);
+ break;
+ case PROP_INT_MASTER_READY:
+ g_value_set_boolean (value, priv->master_ready);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -346,14 +717,32 @@ dispose (GObject *object)
{
NMActiveConnectionPrivate *priv = NM_ACTIVE_CONNECTION_GET_PRIVATE (object);
+ if (priv->chain) {
+ nm_auth_chain_unref (priv->chain);
+ priv->chain = NULL;
+ }
+
g_free (priv->path);
priv->path = NULL;
g_free (priv->specific_object);
priv->specific_object = NULL;
g_clear_object (&priv->connection);
+
+ if (priv->device_state_id) {
+ g_assert (priv->device);
+ g_signal_handler_disconnect (priv->device, priv->device_state_id);
+ priv->device_state_id = 0;
+ }
g_clear_object (&priv->device);
+
+ if (priv->master) {
+ g_signal_handlers_disconnect_by_func (priv->master,
+ (GCallback) master_state_cb,
+ NM_ACTIVE_CONNECTION (object));
+ }
g_clear_object (&priv->master);
+ g_clear_object (&priv->subject);
G_OBJECT_CLASS (nm_active_connection_parent_class)->dispose (object);
}
@@ -368,6 +757,7 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
/* virtual methods */
object_class->get_property = get_property;
object_class->set_property = set_property;
+ object_class->constructed = constructed;
object_class->dispose = dispose;
/* D-Bus exported properties */
@@ -449,28 +839,27 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
"Internal device",
"Internal device",
NM_TYPE_DEVICE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ G_PARAM_READWRITE));
- g_object_class_install_property (object_class, PROP_INT_USER_REQUESTED,
- g_param_spec_boolean (NM_ACTIVE_CONNECTION_INT_USER_REQUESTED,
- "User requested",
- "User requested",
- FALSE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
-
- g_object_class_install_property (object_class, PROP_INT_USER_UID,
- g_param_spec_ulong (NM_ACTIVE_CONNECTION_INT_USER_UID,
- "User UID",
- "User UID (if user requested)",
- 0, G_MAXULONG, 0,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ g_object_class_install_property (object_class, PROP_INT_SUBJECT,
+ g_param_spec_object (NM_ACTIVE_CONNECTION_INT_SUBJECT,
+ "Subject",
+ "Subject",
+ NM_TYPE_AUTH_SUBJECT,
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
g_object_class_install_property (object_class, PROP_INT_MASTER,
g_param_spec_object (NM_ACTIVE_CONNECTION_INT_MASTER,
- "Internal master device",
- "Internal device",
- NM_TYPE_DEVICE,
- G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY));
+ "Internal master active connection",
+ "Internal active connection",
+ NM_TYPE_ACTIVE_CONNECTION,
+ G_PARAM_READWRITE));
+
+ g_object_class_install_property (object_class, PROP_INT_MASTER_READY,
+ g_param_spec_boolean (NM_ACTIVE_CONNECTION_INT_MASTER_READY,
+ "Internal master active connection ready for slaves",
+ "Internal active connection ready",
+ FALSE, G_PARAM_READABLE));
nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
G_TYPE_FROM_CLASS (ac_class),
diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h
index 96bbfedd75..fa9e5fde4c 100644
--- a/src/nm-active-connection.h
+++ b/src/nm-active-connection.h
@@ -24,6 +24,7 @@
#include <glib-object.h>
#include "nm-types.h"
#include "nm-connection.h"
+#include "nm-auth-subject.h"
#define NM_TYPE_ACTIVE_CONNECTION (nm_active_connection_get_type ())
#define NM_ACTIVE_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ACTIVE_CONNECTION, NMActiveConnection))
@@ -43,13 +44,12 @@
#define NM_ACTIVE_CONNECTION_VPN "vpn"
#define NM_ACTIVE_CONNECTION_MASTER "master"
-/* Internal non-exported construct-time properties */
+/* Internal non-exported properties */
#define NM_ACTIVE_CONNECTION_INT_CONNECTION "int-connection"
#define NM_ACTIVE_CONNECTION_INT_DEVICE "int-device"
-#define NM_ACTIVE_CONNECTION_INT_USER_REQUESTED "int-user-requested"
-#define NM_ACTIVE_CONNECTION_INT_USER_UID "int-user-uid"
+#define NM_ACTIVE_CONNECTION_INT_SUBJECT "int-subject"
#define NM_ACTIVE_CONNECTION_INT_MASTER "int-master"
-
+#define NM_ACTIVE_CONNECTION_INT_MASTER_READY "int-master-ready"
typedef struct {
GObject parent;
@@ -58,13 +58,36 @@ typedef struct {
typedef struct {
GObjectClass parent;
+ /* re-emits device state changes as a convenience for subclasses for
+ * device states >= DISCONNECTED.
+ */
+ void (*device_state_changed) (NMActiveConnection *connection,
+ NMDevice *device,
+ NMDeviceState new_state,
+ NMDeviceState old_state);
+ void (*master_failed) (NMActiveConnection *connection);
} NMActiveConnectionClass;
GType nm_active_connection_get_type (void);
+typedef void (*NMActiveConnectionAuthResultFunc) (NMActiveConnection *self,
+ gboolean success,
+ const char *error_desc,
+ gpointer user_data1,
+ gpointer user_data2);
+
+void nm_active_connection_authorize (NMActiveConnection *self,
+ NMActiveConnectionAuthResultFunc result_func,
+ gpointer user_data1,
+ gpointer user_data2);
+
void nm_active_connection_export (NMActiveConnection *self);
NMConnection *nm_active_connection_get_connection (NMActiveConnection *self);
+
+void nm_active_connection_set_connection (NMActiveConnection *self,
+ NMConnection *connection);
+
const char * nm_active_connection_get_name (NMActiveConnection *self);
const char * nm_active_connection_get_path (NMActiveConnection *self);
@@ -91,10 +114,19 @@ void nm_active_connection_set_state (NMActiveConnection *self,
NMDevice * nm_active_connection_get_device (NMActiveConnection *self);
+gboolean nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device);
+
+NMAuthSubject *nm_active_connection_get_subject (NMActiveConnection *self);
+
gboolean nm_active_connection_get_user_requested (NMActiveConnection *self);
gulong nm_active_connection_get_user_uid (NMActiveConnection *self);
-NMDevice * nm_active_connection_get_master (NMActiveConnection *self);
+NMActiveConnection *nm_active_connection_get_master (NMActiveConnection *self);
+
+gboolean nm_active_connection_get_master_ready (NMActiveConnection *self);
+
+void nm_active_connection_set_master (NMActiveConnection *self,
+ NMActiveConnection *master);
#endif /* NM_ACTIVE_CONNECTION_H */
diff --git a/src/nm-auth-subject.c b/src/nm-auth-subject.c
new file mode 100644
index 0000000000..66c0d4e63e
--- /dev/null
+++ b/src/nm-auth-subject.c
@@ -0,0 +1,210 @@
+/* -*- 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.
+ *
+ * Copyright (C) 2013 Red Hat, Inc.
+ */
+
+/**
+ * SECTION:nm-auth-subject
+ * @short_description: Encapsulates authentication information about a requestor
+ *
+ * #NMAuthSubject encpasulates identifying information about an entity that
+ * makes requests, like process identifier and user UID.
+ */
+
+#include <config.h>
+#include <glib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#if WITH_POLKIT
+#include <polkit/polkit.h>
+#endif
+
+#include "nm-auth-subject.h"
+#include "nm-dbus-manager.h"
+
+G_DEFINE_TYPE (NMAuthSubject, nm_auth_subject, G_TYPE_OBJECT)
+
+#define NM_AUTH_SUBJECT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_AUTH_SUBJECT, NMAuthSubjectPrivate))
+
+typedef struct {
+ gulong pid;
+ gulong uid;
+ char *dbus_sender;
+
+#if WITH_POLKIT
+ PolkitSubject *pk_subject;
+#endif
+} NMAuthSubjectPrivate;
+
+static NMAuthSubject *
+_new_common (DBusGMethodInvocation *context,
+ DBusConnection *connection,
+ DBusMessage *message,
+ gboolean internal)
+{
+ NMAuthSubject *subject;
+ NMAuthSubjectPrivate *priv;
+ NMDBusManager *dbus_mgr;
+ gboolean success = FALSE;
+
+ g_return_val_if_fail (context || (connection && message) || internal, NULL);
+ if (internal)
+ g_return_val_if_fail (context == NULL && connection == NULL && message == NULL, NULL);
+
+ subject = NM_AUTH_SUBJECT (g_object_new (NM_TYPE_AUTH_SUBJECT, NULL));
+ priv = NM_AUTH_SUBJECT_GET_PRIVATE (subject);
+
+ dbus_mgr = nm_dbus_manager_get ();
+
+ if (internal) {
+ priv->uid = 0;
+ priv->pid = 0;
+ return subject;
+ }
+
+ if (context) {
+ success = nm_dbus_manager_get_caller_info (dbus_mgr,
+ context,
+ &priv->dbus_sender,
+ &priv->uid,
+ &priv->pid);
+ } else if (message) {
+ success = nm_dbus_manager_get_caller_info_from_message (dbus_mgr,
+ connection,
+ message,
+ &priv->dbus_sender,
+ &priv->uid,
+ &priv->pid);
+ } else
+ g_assert_not_reached ();
+
+ if (!success) {
+ g_object_unref (subject);
+ return NULL;
+ }
+
+ g_assert (priv->dbus_sender);
+ g_assert_cmpuint (priv->pid, !=, 0);
+
+#if WITH_POLKIT
+ /* FIXME: should we use polkit_unix_session_new() to store the session ID
+ * of a short-lived process, so that the process can exit but we can still
+ * ask that user for authorization?
+ */
+ priv->pk_subject = polkit_unix_process_new_for_owner (priv->pid, 0, priv->uid);
+ if (!priv->pk_subject)
+ return NULL;
+#endif
+
+ return subject;
+}
+
+
+NMAuthSubject *
+nm_auth_subject_new_from_context (DBusGMethodInvocation *context)
+{
+ return _new_common (context, NULL, NULL, FALSE);
+}
+
+NMAuthSubject *
+nm_auth_subject_new_from_message (DBusConnection *connection,
+ DBusMessage *message)
+{
+ return _new_common (NULL, connection, message, FALSE);
+}
+
+/**
+ * nm_auth_subject_new_internal():
+ *
+ * Creates a new auth subject representing the NetworkManager process itself.
+ *
+ * Returns: the new #NMAuthSubject
+ */
+NMAuthSubject *
+nm_auth_subject_new_internal (void)
+{
+ return _new_common (NULL, NULL, NULL, TRUE);
+}
+
+/**************************************************************/
+
+gulong
+nm_auth_subject_get_uid (NMAuthSubject *subject)
+{
+ return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->uid;
+}
+
+const char *
+nm_auth_subject_get_dbus_sender (NMAuthSubject *subject)
+{
+ return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->dbus_sender;
+}
+
+gboolean
+nm_auth_subject_get_internal (NMAuthSubject *subject)
+{
+ /* internal requests will have no dbus sender */
+ return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->dbus_sender ? FALSE : TRUE;
+}
+
+#if WITH_POLKIT
+PolkitSubject *
+nm_auth_subject_get_polkit_subject (NMAuthSubject *subject)
+{
+ return NM_AUTH_SUBJECT_GET_PRIVATE (subject)->pk_subject;
+}
+#endif
+
+/******************************************************************/
+
+static void
+nm_auth_subject_init (NMAuthSubject *self)
+{
+ NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (self);
+
+ priv->pid = G_MAXULONG;
+ priv->uid = G_MAXULONG;
+}
+
+static void
+finalize (GObject *object)
+{
+ NMAuthSubjectPrivate *priv = NM_AUTH_SUBJECT_GET_PRIVATE (object);
+
+ g_free (priv->dbus_sender);
+
+#if WITH_POLKIT
+ if (priv->pk_subject)
+ g_object_unref (priv->pk_subject);
+#endif
+
+ G_OBJECT_CLASS (nm_auth_subject_parent_class)->finalize (object);
+}
+
+static void
+nm_auth_subject_class_init (NMAuthSubjectClass *config_class)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (config_class);
+
+ g_type_class_add_private (config_class, sizeof (NMAuthSubjectPrivate));
+
+ /* virtual methods */
+ object_class->finalize = finalize;
+}
diff --git a/src/nm-auth-subject.h b/src/nm-auth-subject.h
new file mode 100644
index 0000000000..8f049a8405
--- /dev/null
+++ b/src/nm-auth-subject.h
@@ -0,0 +1,68 @@
+/* -*- 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.
+ *
+ * Copyright (C) 2013 Red Hat, Inc.
+ */
+
+#ifndef NM_AUTH_SUBJECT_H
+#define NM_AUTH_SUBJECT_H
+
+#include <config.h>
+#include <glib.h>
+#include <glib-object.h>
+#include <dbus/dbus.h>
+#include <dbus/dbus-glib.h>
+
+#if WITH_POLKIT
+#include <polkit/polkit.h>
+#endif
+
+#define NM_TYPE_AUTH_SUBJECT (nm_auth_subject_get_type ())
+#define NM_AUTH_SUBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_AUTH_SUBJECT, NMAuthSubject))
+#define NM_AUTH_SUBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_AUTH_SUBJECT, NMAuthSubjectClass))
+#define NM_IS_AUTH_SUBJECT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_AUTH_SUBJECT))
+#define NM_IS_AUTH_SUBJECT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_AUTH_SUBJECT))
+#define NM_AUTH_SUBJECT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_AUTH_SUBJECT, NMAuthSubjectClass))
+
+typedef struct {
+ GObject parent;
+} NMAuthSubject;
+
+typedef struct {
+ GObjectClass parent;
+
+} NMAuthSubjectClass;
+
+GType nm_auth_subject_get_type (void);
+
+NMAuthSubject *nm_auth_subject_new_from_context (DBusGMethodInvocation *context);
+
+NMAuthSubject *nm_auth_subject_new_from_message (DBusConnection *connection, DBusMessage *message);
+
+NMAuthSubject *nm_auth_subject_new_internal (void);
+
+gulong nm_auth_subject_get_uid (NMAuthSubject *subject);
+
+const char *nm_auth_subject_get_dbus_sender (NMAuthSubject *subject);
+
+gboolean nm_auth_subject_get_internal (NMAuthSubject *subject);
+
+#if WITH_POLKIT
+PolkitSubject *nm_auth_subject_get_polkit_subject (NMAuthSubject *subject);
+#endif
+
+#endif /* NM_AUTH_SUBJECT_H */
diff --git a/src/nm-dbus-manager.c b/src/nm-dbus-manager.c
index 891a765f46..e9d5fce5c1 100644
--- a/src/nm-dbus-manager.c
+++ b/src/nm-dbus-manager.c
@@ -267,6 +267,27 @@ private_server_get_connection_owner (PrivateServer *s, DBusGConnection *connecti
/**************************************************************/
+static gboolean
+_bus_get_unix_pid (NMDBusManager *self,
+ const char *sender,
+ gulong *out_pid,
+ GError **error)
+{
+ guint32 unix_pid = G_MAXUINT32;
+
+ if (!dbus_g_proxy_call_with_timeout (NM_DBUS_MANAGER_GET_PRIVATE (self)->proxy,
+ "GetConnectionUnixProcessID", 2000, error,
+ G_TYPE_STRING, sender,
+ G_TYPE_INVALID,
+ G_TYPE_UINT, &unix_pid,
+ G_TYPE_INVALID)) {
+ return FALSE;
+ }
+
+ *out_pid = (gulong) unix_pid;
+ return TRUE;
+}
+
/**
* _get_caller_info_from_context():
*
@@ -279,7 +300,8 @@ _get_caller_info (NMDBusManager *self,
DBusConnection *connection,
DBusMessage *message,
char **out_sender,
- gulong *out_uid)
+ gulong *out_uid,
+ gulong *out_pid)
{
NMDBusManagerPrivate *priv = NM_DBUS_MANAGER_GET_PRIVATE (self);
DBusGConnection *gconn;
@@ -312,6 +334,10 @@ _get_caller_info (NMDBusManager *self,
*out_uid = 0;
if (out_sender)
*out_sender = g_strdup (priv_sender);
+ if (out_pid) {
+ if (!dbus_connection_get_unix_process_id (connection, out_pid))
+ *out_pid = G_MAXULONG;
+ }
return TRUE;
}
}
@@ -331,6 +357,14 @@ _get_caller_info (NMDBusManager *self,
}
}
+ if (out_pid) {
+ if (!_bus_get_unix_pid (self, sender, out_pid, NULL)) {
+ *out_pid = G_MAXULONG;
+ g_free (sender);
+ return FALSE;
+ }
+ }
+
if (out_sender)
*out_sender = g_strdup (sender);
@@ -342,9 +376,10 @@ gboolean
nm_dbus_manager_get_caller_info (NMDBusManager *self,
DBusGMethodInvocation *context,
char **out_sender,
- gulong *out_uid)
+ gulong *out_uid,
+ gulong *out_pid)
{
- return _get_caller_info (self, context, NULL, NULL, out_sender, out_uid);
+ return _get_caller_info (self, context, NULL, NULL, out_sender, out_uid, out_pid);
}
gboolean
@@ -352,9 +387,10 @@ nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self,
DBusConnection *connection,
DBusMessage *message,
char **out_sender,
- gulong *out_uid)
+ gulong *out_uid,
+ gulong *out_pid)
{
- return _get_caller_info (self, NULL, connection, message, out_sender, out_uid);
+ return _get_caller_info (self, NULL, connection, message, out_sender, out_uid, out_pid);
}
gboolean
diff --git a/src/nm-dbus-manager.h b/src/nm-dbus-manager.h
index 319252e87f..7895a20375 100644
--- a/src/nm-dbus-manager.h
+++ b/src/nm-dbus-manager.h
@@ -87,7 +87,8 @@ DBusGConnection * nm_dbus_manager_get_connection (NMDBusManager *self);
gboolean nm_dbus_manager_get_caller_info (NMDBusManager *self,
DBusGMethodInvocation *context,
char **out_sender,
- gulong *out_uid);
+ gulong *out_uid,
+ gulong *out_pid);
gboolean nm_dbus_manager_get_unix_user (NMDBusManager *self,
const char *sender,
@@ -97,7 +98,8 @@ gboolean nm_dbus_manager_get_caller_info_from_message (NMDBusManager *self,
DBusConnection *connection,
DBusMessage *message,
char **out_sender,
- gulong *out_uid);
+ gulong *out_uid,
+ gulong *out_pid);
void nm_dbus_manager_register_exported_type (NMDBusManager *self,
GType object_type,
diff --git a/src/nm-manager-auth.c b/src/nm-manager-auth.c
index eea74f2152..57f5c72569 100644
--- a/src/nm-manager-auth.c
+++ b/src/nm-manager-auth.c
@@ -31,6 +31,7 @@
#include "nm-manager-auth.h"
#include "nm-logging.h"
#include "nm-dbus-manager.h"
+#include "nm-auth-subject.h"
struct NMAuthChain {
guint32 refcount;
@@ -43,6 +44,7 @@ struct NMAuthChain {
DBusGMethodInvocation *context;
char *owner;
gulong user_uid;
+ NMAuthSubject *subject;
GError *error;
guint idle_id;
@@ -105,16 +107,16 @@ pk_authority_get (GError **error)
#endif
static NMAuthChain *
-_auth_chain_new (DBusGMethodInvocation *context,
- DBusMessage *message,
+_auth_chain_new (NMAuthSubject *subject,
const char *dbus_sender,
gulong user_uid,
+ DBusGMethodInvocation *context,
NMAuthChainResultFunc done_func,
gpointer user_data)
{
NMAuthChain *self;
- g_return_val_if_fail (message || dbus_sender, NULL);
+ g_return_val_if_fail (subject || user_uid == 0 || dbus_sender, NULL);
self = g_malloc0 (sizeof (NMAuthChain));
self->refcount = 1;
@@ -125,65 +127,73 @@ _auth_chain_new (DBusGMethodInvocation *context,
self->done_func = done_func;
self->user_data = user_data;
self->context = context;
- self->user_uid = user_uid;
- if (message)
- self->owner = g_strdup (dbus_message_get_sender (message));
- else if (dbus_sender)
+ if (subject) {
+ self->user_uid = nm_auth_subject_get_uid (subject);
+ self->subject = g_object_ref (subject);
+ } else {
+ self->user_uid = user_uid;
self->owner = g_strdup (dbus_sender);
-
- if (user_uid > 0 && !self->owner) {
- /* Need an owner */
- g_warn_if_fail (self->owner);
- nm_auth_chain_unref (self);
- self = NULL;
+ if (user_uid > 0 && !self->owner) {
+ /* Need an owner */
+ g_warn_if_fail (self->owner);
+ nm_auth_chain_unref (self);
+ self = NULL;
+ }
}
return self;
}
NMAuthChain *
-nm_auth_chain_new (DBusGMethodInvocation *context,
- NMAuthChainResultFunc done_func,
- gpointer user_data,
- const char **out_error_desc)
+nm_auth_chain_new_dbus_sender (const char *dbus_sender,
+ gulong user_uid,
+ NMAuthChainResultFunc done_func,
+ gpointer user_data)
+{
+ return _auth_chain_new (NULL, dbus_sender, user_uid, NULL, done_func, user_data);
+}
+
+/* Creates the NMAuthSubject automatically */
+NMAuthChain *
+nm_auth_chain_new_context (DBusGMethodInvocation *context,
+ NMAuthChainResultFunc done_func,
+ gpointer user_data)
{
- gulong sender_uid = G_MAXULONG;
- char *sender = NULL;
- NMAuthChain *chain = NULL;
+ NMAuthSubject *subject;
+ NMAuthChain *chain;
g_return_val_if_fail (context != NULL, NULL);
- if (nm_dbus_manager_get_caller_info (nm_dbus_manager_get (),
- context,
- &sender,
- &sender_uid)) {
- chain = _auth_chain_new (context, NULL, sender, sender_uid, done_func, user_data);
- }
-
- if (!chain && out_error_desc)
- *out_error_desc = "Unable to determine request UID and sender.";
+ subject = nm_auth_subject_new_from_context (context);
+ if (!subject)
+ return NULL;
- g_free (sender);
+ chain = nm_auth_chain_new_subject (subject,
+ context,
+ done_func,
+ user_data);
+ g_object_unref (subject);
return chain;
}
+/* Requires an NMAuthSubject */
NMAuthChain *
-nm_auth_chain_new_raw_message (DBusMessage *message,
- gulong user_uid,
- NMAuthChainResultFunc done_func,
- gpointer user_data)
+nm_auth_chain_new_subject (NMAuthSubject *subject,
+ DBusGMethodInvocation *context,
+ NMAuthChainResultFunc done_func,
+ gpointer user_data)
{
- return _auth_chain_new (NULL, message, NULL, user_uid, done_func, user_data);
-}
+ NMAuthChain *chain;
-NMAuthChain *
-nm_auth_chain_new_dbus_sender (const char *dbus_sender,
- gulong user_uid,
- NMAuthChainResultFunc done_func,
- gpointer user_data)
-{
- return _auth_chain_new (NULL, NULL, dbus_sender, user_uid, done_func, user_data);
+ g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL);
+ chain = _auth_chain_new (subject, NULL, G_MAXULONG, context, done_func, user_data);
+
+ /* Chains creation from a valid NMAuthSubject cannot fail since the
+ * subject already has all the necessary auth info.
+ */
+ g_assert (chain);
+ return chain;
}
gpointer
@@ -422,7 +432,7 @@ _add_call_polkit (NMAuthChain *self,
AuthCall *call;
g_return_val_if_fail (self != NULL, FALSE);
- g_return_val_if_fail (self->owner != NULL, FALSE);
+ g_return_val_if_fail (self->owner || self->subject, FALSE);
g_return_val_if_fail (permission != NULL, FALSE);
call = auth_call_new (self, permission);
@@ -433,10 +443,16 @@ _add_call_polkit (NMAuthChain *self,
return FALSE;
}
- subject = polkit_system_bus_name_new (self->owner);
- if (!subject) {
- auth_call_schedule_complete_with_error (call, "Failed to create polkit subject");
- return FALSE;
+ if (self->subject) {
+ subject = g_object_ref (nm_auth_subject_get_polkit_subject (self->subject));
+ g_assert (subject);
+ } else {
+ g_assert (self->owner);
+ subject = polkit_system_bus_name_new (self->owner);
+ if (!subject) {
+ auth_call_schedule_complete_with_error (call, "Failed to create polkit subject");
+ return FALSE;
+ }
}
if (allow_interaction)
@@ -496,6 +512,7 @@ nm_auth_chain_unref (NMAuthChain *self)
g_object_unref (self->authority);
#endif
g_free (self->owner);
+ g_object_unref (self->subject);
for (iter = self->calls; iter; iter = g_slist_next (iter))
auth_call_cancel ((AuthCall *) iter->data);
diff --git a/src/nm-manager-auth.h b/src/nm-manager-auth.h
index ebfb707254..43dd639873 100644
--- a/src/nm-manager-auth.h
+++ b/src/nm-manager-auth.h
@@ -27,6 +27,7 @@
#include <nm-connection.h>
#include "nm-dbus-manager.h"
#include "nm-session-monitor.h"
+#include "nm-auth-subject.h"
#define NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK "org.freedesktop.NetworkManager.enable-disable-network"
#define NM_AUTH_PERMISSION_SLEEP_WAKE "org.freedesktop.NetworkManager.sleep-wake"
@@ -55,21 +56,20 @@ typedef void (*NMAuthChainResultFunc) (NMAuthChain *chain,
DBusGMethodInvocation *context,
gpointer user_data);
-NMAuthChain *nm_auth_chain_new (DBusGMethodInvocation *context,
- NMAuthChainResultFunc done_func,
- gpointer user_data,
- const char **out_error_desc);
-
-NMAuthChain *nm_auth_chain_new_raw_message (DBusMessage *message,
- gulong user_uid,
- NMAuthChainResultFunc done_func,
- gpointer user_data);
-
NMAuthChain *nm_auth_chain_new_dbus_sender (const char *dbus_sender,
gulong user_uid,
NMAuthChainResultFunc done_func,
gpointer user_data);
+NMAuthChain *nm_auth_chain_new_context (DBusGMethodInvocation *context,
+ NMAuthChainResultFunc done_func,
+ gpointer user_data);
+
+NMAuthChain *nm_auth_chain_new_subject (NMAuthSubject *subject,
+ DBusGMethodInvocation *context,
+ NMAuthChainResultFunc done_func,
+ gpointer user_data);
+
gpointer nm_auth_chain_get_data (NMAuthChain *chain, const char *tag);
gpointer nm_auth_chain_steal_data (NMAuthChain *chain, const char *tag);
diff --git a/src/nm-manager.c b/src/nm-manager.c
index d6e6f57cef..af663c95ab 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -156,16 +156,14 @@ static void remove_device (NMManager *self, NMDevice *device, gboolean quitting)
static void hostname_provider_init (NMHostnameProvider *provider_class);
-static NMActiveConnection *internal_activate_device (NMManager *manager,
- NMDevice *device,
- NMConnection *connection,
- const char *specific_object,
- gboolean user_requested,
- gulong sender_uid,
- const char *dbus_sender,
- gboolean assumed,
- NMActiveConnection *master,
- GError **error);
+static NMActiveConnection *_new_active_connection (NMManager *self,
+ NMConnection *connection,
+ const char *specific_object,
+ NMDevice *device,
+ NMAuthSubject *subject,
+ GError **error);
+
+static void policy_activating_device_changed (GObject *object, GParamSpec *pspec, gpointer user_data);
static NMDevice *find_device_by_ip_iface (NMManager *self, const gchar *iface);
@@ -181,24 +179,6 @@ platform_link_added_cb (NMPlatform *platform,
#define SSD_POKE_INTERVAL 120
#define ORIGDEV_TAG "originating-device"
-typedef struct PendingActivation PendingActivation;
-typedef void (*PendingActivationFunc) (PendingActivation *pending,
- GError *error);
-
-struct PendingActivation {
- NMManager *manager;
-
- DBusGMethodInvocation *context;
- PendingActivationFunc callback;
- NMAuthChain *chain;
- const char *wifi_shared_permission;
-
- char *connection_path;
- NMConnection *connection;
- char *specific_object_path;
- char *device_path;
-};
-
typedef struct {
gboolean user_enabled;
gboolean daemon_enabled;
@@ -334,12 +314,19 @@ static void active_connection_state_changed (NMActiveConnection *active,
GParamSpec *pspec,
NMManager *self);
-static void
-active_connection_removed (NMManager *self, NMActiveConnection *active)
+/* Returns: whether to notify D-Bus of the removal or not */
+static gboolean
+active_connection_remove (NMManager *self, NMActiveConnection *active)
{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ gboolean notify = !!nm_active_connection_get_path (active);
+
+ priv->active_connections = g_slist_remove (priv->active_connections, active);
g_signal_emit (self, signals[ACTIVE_CONNECTION_REMOVED], 0, active);
g_signal_handlers_disconnect_by_func (active, active_connection_state_changed, self);
g_object_unref (active);
+
+ return notify;
}
static gboolean
@@ -348,24 +335,21 @@ _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;
+ g_object_freeze_notify (G_OBJECT (self));
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);
- active_connection_removed (self, ac);
- changed = TRUE;
+ if (active_connection_remove (self, ac))
+ g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
}
}
-
- if (changed)
- g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
+ g_object_thaw_notify (G_OBJECT (self));
return FALSE;
}
@@ -403,7 +387,10 @@ active_connection_add (NMManager *self, NMActiveConnection *active)
self);
g_signal_emit (self, signals[ACTIVE_CONNECTION_ADDED], 0, active);
- g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
+
+ /* Only notify D-Bus if the active connection is actually exported */
+ if (nm_active_connection_get_path (active))
+ g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
}
const GSList *
@@ -424,7 +411,7 @@ active_connection_get_by_path (NMManager *manager, const char *path)
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)
+ if (g_strcmp0 (path, nm_active_connection_get_path (candidate)) == 0)
return candidate;
}
return NULL;
@@ -846,246 +833,6 @@ nm_manager_get_state (NMManager *manager)
return NM_MANAGER_GET_PRIVATE (manager)->state;
}
-static gboolean
-might_be_vpn (NMConnection *connection)
-{
- NMSettingConnection *s_con;
- const char *ctype = NULL;
-
- if (nm_connection_get_setting_vpn (connection))
- return TRUE;
-
- /* Make sure it's not a VPN, which we can't autocomplete yet */
- s_con = nm_connection_get_setting_connection (connection);
- 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);
-
- if (!nm_connection_get_setting_vpn (connection)) {
- 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"),
- NULL,
- FALSE); /* No IPv6 by default for now */
-
- return TRUE;
-}
-
-static PendingActivation *
-pending_activation_new (NMManager *manager,
- DBusGMethodInvocation *context,
- const char *device_path,
- const char *connection_path,
- GHashTable *settings,
- const char *specific_object_path,
- PendingActivationFunc callback,
- GError **error)
-{
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
- PendingActivation *pending;
- NMDevice *device = NULL;
- NMConnection *connection = NULL;
- GSList *all_connections = NULL;
- gboolean success;
-
- 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);
-
- /* A object path of "/" means NULL */
- if (g_strcmp0 (specific_object_path, "/") == 0)
- specific_object_path = NULL;
- if (g_strcmp0 (device_path, "/") == 0)
- device_path = NULL;
-
- /* Create the partial connection from the given settings */
- if (settings) {
- if (device_path)
- device = nm_manager_get_device_by_path (manager, device_path);
- 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);
-
- 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);
- }
- g_slist_free (all_connections);
-
- if (success == FALSE) {
- g_object_unref (connection);
- return NULL;
- }
- }
-
- pending = g_slice_new0 (PendingActivation);
- pending->manager = manager;
- pending->context = context;
- pending->callback = callback;
-
- pending->connection_path = g_strdup (connection_path);
- pending->connection = connection;
-
- /* "/" 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);
- if (device_path && strcmp (device_path, "/"))
- pending->device_path = g_strdup (device_path);
-
- return pending;
-}
-
-static void
-pending_auth_done (NMAuthChain *chain,
- GError *error,
- DBusGMethodInvocation *context,
- gpointer user_data)
-{
- PendingActivation *pending = user_data;
- NMAuthCallResult result;
- GError *tmp_error = NULL;
-
- /* Caller has had a chance to obtain authorization, so we only need to
- * check for 'yes' here.
- */
- 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) {
- tmp_error = g_error_new_literal (NM_MANAGER_ERROR,
- NM_MANAGER_ERROR_PERMISSION_DENIED,
- "Not authorized to control networking.");
- } else if (pending->wifi_shared_permission) {
- 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.");
- }
- }
-
- pending->callback (pending, tmp_error);
- g_clear_error (&tmp_error);
-}
-
-static void
-pending_activation_check_authorized (PendingActivation *pending)
-{
- GError *error;
- const char *wifi_permission = NULL;
- NMConnection *connection;
- NMSettings *settings;
- const char *error_desc = NULL;
-
- g_return_if_fail (pending != NULL);
-
- /* 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;
- }
-
- /* First check if the user is allowed to use networking at all, giving
- * the user a chance to authenticate to gain the permission.
- */
- pending->chain = nm_auth_chain_new (pending->context,
- pending_auth_done,
- 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);
- }
-}
-
-static void
-pending_activation_destroy (PendingActivation *pending,
- GError *error,
- NMActiveConnection *ac)
-{
- g_return_if_fail (pending != NULL);
-
- if (error)
- dbus_g_method_return_error (pending->context, error);
- else if (ac) {
- if (pending->connection) {
- dbus_g_method_return (pending->context,
- pending->connection_path,
- nm_active_connection_get_path (ac));
- } else {
- dbus_g_method_return (pending->context,
- nm_active_connection_get_path (ac));
- }
- }
-
- g_free (pending->connection_path);
- g_free (pending->specific_object_path);
- g_free (pending->device_path);
- if (pending->connection)
- g_object_unref (pending->connection);
-
- if (pending->chain)
- nm_auth_chain_unref (pending->chain);
-
- memset (pending, 0, sizeof (PendingActivation));
- g_slice_free (PendingActivation, pending);
-}
-
/*******************************************************************/
/* Settings stuff via NMSettings */
/*******************************************************************/
@@ -1886,6 +1633,8 @@ device_auth_done_cb (NMAuthChain *chain,
const char *permission;
NMDeviceAuthRequestFunc callback;
+ g_assert (context);
+
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
permission = nm_auth_chain_get_data (chain, "requested-permission");
@@ -1935,25 +1684,24 @@ device_auth_request_cb (NMDevice *device,
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
GError *error = NULL;
NMAuthChain *chain;
- const char *error_desc = NULL;
/* Validate the request */
- chain = nm_auth_chain_new (context, device_auth_done_cb, self, &error_desc);
- if (chain) {
- priv->auth_chains = g_slist_append (priv->auth_chains, chain);
-
- nm_auth_chain_set_data (chain, "device", g_object_ref (device), g_object_unref);
- nm_auth_chain_set_data (chain, "requested-permission", g_strdup (permission), g_free);
- nm_auth_chain_set_data (chain, "callback", callback, NULL);
- nm_auth_chain_set_data (chain, "user-data", user_data, NULL);
- nm_auth_chain_add_call (chain, permission, allow_interaction);
- } else {
+ chain = nm_auth_chain_new_context (context, device_auth_done_cb, self);
+ if (!chain) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
- error_desc);
+ "Unable to authenticate request.");
callback (device, context, error, user_data);
- g_error_free (error);
+ g_clear_error (&error);
+ return;
}
+
+ priv->auth_chains = g_slist_append (priv->auth_chains, chain);
+ nm_auth_chain_set_data (chain, "device", g_object_ref (device), g_object_unref);
+ nm_auth_chain_set_data (chain, "requested-permission", g_strdup (permission), g_free);
+ nm_auth_chain_set_data (chain, "callback", callback, NULL);
+ nm_auth_chain_set_data (chain, "user-data", user_data, NULL);
+ nm_auth_chain_add_call (chain, permission, allow_interaction);
}
/* This should really be moved to gsystem. */
@@ -2167,22 +1915,35 @@ add_device (NMManager *self, NMDevice *device)
/* If the device has a connection it can assume, do that now */
if (connection && nm_device_can_activate (device, connection)) {
- NMActiveConnection *ac;
+ NMActiveConnection *active;
+ NMAuthSubject *subject;
GError *error = NULL;
nm_log_dbg (LOGD_DEVICE, "(%s): will attempt to assume connection",
nm_device_get_iface (device));
- ac = internal_activate_device (self, device, connection, NULL, FALSE, 0, NULL, TRUE, NULL, &error);
- if (ac)
- active_connection_add (self, ac);
- else {
+ /* Tear down any existing connection */
+ if (nm_device_get_act_request (device)) {
+ nm_log_info (LOGD_DEVICE, "(%s): disconnecting for new activation request.",
+ nm_device_get_iface (device));
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_DISCONNECTED,
+ NM_DEVICE_STATE_REASON_NONE);
+ }
+
+ subject = nm_auth_subject_new_internal ();
+ active = _new_active_connection (self, connection, NULL, device, subject, &error);
+ if (active) {
+ active_connection_add (self, active);
+ nm_device_activate (device, NM_ACT_REQUEST (active));
+ } else {
nm_log_warn (LOGD_DEVICE, "assumed connection %s failed to activate: (%d) %s",
nm_connection_get_path (connection),
error ? error->code : -1,
error && error->message ? error->message : "(unknown)");
g_error_free (error);
}
+ g_object_unref (subject);
}
}
@@ -2640,54 +2401,6 @@ impl_manager_get_device_by_ip_iface (NMManager *self,
return path ? TRUE : FALSE;
}
-static NMActiveConnection *
-internal_activate_device (NMManager *manager,
- NMDevice *device,
- NMConnection *connection,
- const char *specific_object,
- gboolean user_requested,
- gulong sender_uid,
- const char *dbus_sender,
- gboolean assumed,
- NMActiveConnection *master,
- GError **error)
-{
- NMActRequest *req;
- NMDevice *master_device = NULL;
-
- g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
- g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
- g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
-
- /* Ensure the requested connection is compatible with the device */
- if (!nm_device_check_connection_compatible (device, connection, error))
- return NULL;
-
- /* Tear down any existing connection */
- if (nm_device_get_act_request (device)) {
- nm_log_info (LOGD_DEVICE, "(%s): disconnecting for new activation request.",
- nm_device_get_iface (device));
- nm_device_state_changed (device,
- NM_DEVICE_STATE_DISCONNECTED,
- NM_DEVICE_STATE_REASON_NONE);
- }
-
- if (master)
- master_device = nm_active_connection_get_device (master);
-
- req = nm_act_request_new (connection,
- specific_object,
- user_requested,
- sender_uid,
- dbus_sender,
- device,
- master_device);
- g_assert (req);
- nm_device_activate (device, req);
-
- return NM_ACTIVE_CONNECTION (req);
-}
-
/**
* find_master:
* @self: #NMManager object
@@ -2800,9 +2513,7 @@ is_compatible_with_slave (NMConnection *master, NMConnection *slave)
* ensure_master_active_connection:
*
* @self: the #NMManager
- * @dbus_sender: if the request was initiated by a user via D-Bus, the
- * dbus sender name of the client that requested the activation; for auto
- * activated connections use %NULL
+ * @subject: the #NMAuthSubject representing the requestor of this activation
* @connection: the connection that should depend on @master_connection
* @device: the #NMDevice, if any, which will activate @connection
* @master_connection: the master connection
@@ -2817,7 +2528,7 @@ is_compatible_with_slave (NMConnection *master, NMConnection *slave)
*/
static NMActiveConnection *
ensure_master_active_connection (NMManager *self,
- const char *dbus_sender,
+ NMAuthSubject *subject,
NMConnection *connection,
NMDevice *device,
NMConnection *master_connection,
@@ -2872,8 +2583,8 @@ ensure_master_active_connection (NMManager *self,
master_ac = nm_manager_activate_connection (self,
candidate,
NULL,
- nm_device_get_path (master_device),
- dbus_sender,
+ master_device,
+ subject,
error);
if (!master_ac)
g_prefix_error (error, "%s", "Master device activation failed: ");
@@ -2920,8 +2631,8 @@ ensure_master_active_connection (NMManager *self,
master_ac = nm_manager_activate_connection (self,
master_connection,
NULL,
- nm_device_get_path (candidate),
- dbus_sender,
+ candidate,
+ subject,
error);
if (!master_ac)
g_prefix_error (error, "%s", "Master device activation failed: ");
@@ -2936,7 +2647,7 @@ ensure_master_active_connection (NMManager *self,
master_connection,
NULL,
NULL,
- dbus_sender,
+ subject,
error);
if (!master_ac)
g_prefix_error (error, "%s", "Master device activation failed: ");
@@ -2954,219 +2665,119 @@ ensure_master_active_connection (NMManager *self,
return NULL;
}
-static NMActiveConnection *
-activate_vpn_connection (NMManager *self,
- NMConnection *connection,
- const char *specific_object,
- gulong sender_uid,
- GError **error)
+static gboolean
+_internal_activate_vpn (NMManager *self, NMActiveConnection *active, GError **error)
{
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- NMActiveConnection *parent = NULL;
- NMDevice *device = NULL;
- GSList *iter;
-
- if (specific_object) {
- /* Find the specifc connection the client requested we use */
- parent = active_connection_get_by_path (self, specific_object);
- if (!parent) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
- "Base connection for VPN connection not active.");
- return NULL;
- }
- } else {
- for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) {
- NMActiveConnection *candidate = iter->data;
+ g_assert (NM_IS_VPN_CONNECTION (active));
- if (nm_active_connection_get_default (candidate)) {
- parent = candidate;
- break;
- }
- }
- }
-
- if (!parent) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
- "Could not find source connection.");
- return NULL;
- }
-
- device = nm_active_connection_get_device (parent);
- if (!device) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "Source connection had no active device.");
- return NULL;
- }
-
- return nm_vpn_manager_activate_connection (priv->vpn_manager,
- connection,
- device,
- nm_active_connection_get_path (parent),
- TRUE,
- sender_uid,
+ return nm_vpn_manager_activate_connection (NM_MANAGER_GET_PRIVATE (self)->vpn_manager,
+ NM_VPN_CONNECTION (active),
error);
}
-NMActiveConnection *
-nm_manager_activate_connection (NMManager *manager,
- NMConnection *connection,
- const char *specific_object,
- const char *device_path,
- const char *dbus_sender,
- GError **error)
+static gboolean
+_internal_activate_device (NMManager *self, NMActiveConnection *active, GError **error)
{
- NMManagerPrivate *priv;
- NMDevice *device = NULL;
- gulong sender_uid = G_MAXULONG;
- char *iface;
- NMDevice *master_device = NULL;
+ NMDevice *device, *master_device = NULL;
+ NMConnection *connection;
NMConnection *master_connection = NULL;
- NMActiveConnection *master_ac = NULL, *ac = NULL;
- gboolean matched;
- g_return_val_if_fail (manager != NULL, NULL);
- g_return_val_if_fail (connection != NULL, NULL);
- g_return_val_if_fail (error != NULL, NULL);
- g_return_val_if_fail (*error == NULL, NULL);
+ g_assert (NM_IS_VPN_CONNECTION (active) == FALSE);
- priv = NM_MANAGER_GET_PRIVATE (manager);
+ connection = nm_active_connection_get_connection (active);
+ g_assert (connection);
- /* Get the UID of the user that originated the request, if any */
- if (dbus_sender) {
- if (!nm_dbus_manager_get_unix_user (priv->dbus_mgr, dbus_sender, &sender_uid)) {
- g_set_error_literal (error,
- NM_MANAGER_ERROR, NM_MANAGER_ERROR_PERMISSION_DENIED,
- "Failed to get unix user for dbus sender");
- return NULL;
- }
- } else {
- /* No sender means an internal/automatic activation request */
- sender_uid = 0;
- }
+ device = nm_active_connection_get_device (active);
+ if (!device) {
+ char *iface;
- /* VPN ? */
- if (nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) {
- ac = activate_vpn_connection (manager, connection, specific_object, sender_uid, error);
- goto activated;
- }
+ g_assert (connection_needs_virtual_device (connection));
- /* Device-based connection */
- if (device_path) {
- device = nm_manager_get_device_by_path (manager, device_path);
- if (!device) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "Device not found");
- return NULL;
- }
+ iface = get_virtual_iface_name (self, connection, NULL);
+ g_assert (iface);
- /* If it's a virtual interface make sure the device given by the
- * path matches the connection's interface details.
+ /* Create the software device. Only exception is when:
+ * - this is an auto-activation *and* the device denies auto-activation
+ * at this time (the device was manually disconnected/deleted before)
*/
- if (connection_needs_virtual_device (connection)) {
- iface = get_virtual_iface_name (manager, connection, NULL);
- if (!iface) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "Failed to determine connection's virtual interface name");
- return NULL;
- }
-
- matched = g_str_equal (iface, nm_device_get_ip_iface (device));
- g_free (iface);
- if (!matched) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "Device given by path did not match connection's virtual interface name");
- return NULL;
+ if (!nm_manager_can_device_auto_connect (self, iface)) {
+ if (nm_active_connection_get_user_requested (active)) {
+ /* Manual activation - allow device auto-activation again */
+ nm_manager_prevent_device_auto_connect (self, iface, FALSE);
+ } else {
+ g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED,
+ "Automatic activation of '%s' not allowed for connection '%s'",
+ iface, nm_connection_get_id (connection));
+ g_free (iface);
+ return FALSE;
}
}
- } else {
- /* Virtual connections (VLAN, bond, team, etc) may not specify
- * a device path because the device may not be created yet,
- * or it be given by the connection's properties instead.
- * Find the device the connection refers to, or create it
- * if needed.
- */
- if (!connection_needs_virtual_device (connection)) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "This connection requires an existing device.");
- return NULL;
- }
-
- iface = get_virtual_iface_name (manager, connection, NULL);
- if (!iface) {
- g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "Failed to determine connection's virtual interface name");
- return NULL;
- }
+ g_free (iface);
- device = find_device_by_ip_iface (manager, iface);
+ device = system_create_virtual_device (self, connection);
if (!device) {
- /* Create the software device. Only exception is when:
- * - this is an auto-activation *and* the device denies auto-activation
- * at this time (the device was manually disconnected/deleted before)
- */
- if (!nm_manager_can_device_auto_connect (manager, iface)) {
- if (dbus_sender) {
- /* Manual activation - allow device auto-activation again */
- nm_manager_prevent_device_auto_connect (manager, iface, FALSE);
- } else {
- g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED,
- "'%s' does not allow automatic connections at this time => software device '%s' not created for '%s'",
- iface, iface, nm_connection_get_id (connection));
- g_free (iface);
- return NULL;
- }
- }
+ g_set_error_literal (error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "Failed to create virtual interface");
+ return FALSE;
+ }
- device = system_create_virtual_device (manager, connection);
- if (!device) {
- g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
- "Failed to create virtual interface '%s'", iface);
- g_free (iface);
- return NULL;
- }
+ if (!nm_active_connection_set_device (active, device)) {
+ g_set_error_literal (error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "The device could not be activated with this connection");
+ return FALSE;
+ }
- /* A newly created device, if allowed to be managed by NM, will be
- * in the UNAVAILABLE state here. To ensure it can be activated
- * immediately, we transition it to DISCONNECTED so it passes the
- * nm_device_can_activate() check below.
- */
- if ( nm_device_is_available (device)
- && (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE)) {
- nm_device_state_changed (device,
- NM_DEVICE_STATE_DISCONNECTED,
- NM_DEVICE_STATE_REASON_NONE);
- }
+ /* A newly created device, if allowed to be managed by NM, will be
+ * in the UNAVAILABLE state here. To ensure it can be activated
+ * immediately, we transition it to DISCONNECTED so it passes the
+ * nm_device_can_activate() check below.
+ */
+ if ( nm_device_is_available (device)
+ && (nm_device_get_state (device) == NM_DEVICE_STATE_UNAVAILABLE)) {
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_DISCONNECTED,
+ NM_DEVICE_STATE_REASON_NONE);
}
- g_free (iface);
}
+ /* Final connection must be compatible with the device */
+ if (!nm_device_check_connection_compatible (device, connection, error))
+ return FALSE;
+
if (!nm_device_can_activate (device, connection)) {
g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNMANAGED_DEVICE,
"Device not managed by NetworkManager or unavailable");
- return NULL;
+ return FALSE;
}
/* If this is an autoconnect request, but the device isn't allowing autoconnect
* right now, we reject it.
*/
- if (!dbus_sender && !nm_device_autoconnect_allowed (device)) {
+ if (!nm_active_connection_get_user_requested (active) &&
+ !nm_device_autoconnect_allowed (device)) {
g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_AUTOCONNECT_NOT_ALLOWED,
"%s does not allow automatic connections at this time",
nm_device_get_iface (device));
- return NULL;
+ return FALSE;
}
/* Try to find the master connection/device if the connection has a dependency */
- if (!find_master (manager, connection, device, &master_connection, &master_device)) {
+ if (!find_master (self, connection, device, &master_connection, &master_device)) {
g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
"Master connection not found or invalid");
- return NULL;
+ return FALSE;
}
/* Ensure there's a master active connection the new connection we're
* activating can depend on.
*/
if (master_connection || master_device) {
+ NMActiveConnection *master_ac = NULL;
+
if (master_connection) {
nm_log_dbg (LOGD_CORE, "Activation of '%s' requires master connection '%s'",
nm_connection_get_id (connection),
@@ -3178,17 +2789,15 @@ nm_manager_activate_connection (NMManager *manager,
nm_device_get_ip_iface (master_device));
}
- /* Ensure eg bond/team slave and the candidate master is
- * a bond/team master
- */
+ /* Ensure eg bond slave and the candidate master is a bond master */
if (master_connection && !is_compatible_with_slave (master_connection, connection)) {
g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED,
"The master connection was not compatible");
- return NULL;
+ return FALSE;
}
- master_ac = ensure_master_active_connection (manager,
- dbus_sender,
+ master_ac = ensure_master_active_connection (self,
+ nm_active_connection_get_subject (active),
connection,
device,
master_connection,
@@ -3197,95 +2806,293 @@ nm_manager_activate_connection (NMManager *manager,
if (!master_ac) {
if (error)
g_assert (*error);
- return NULL;
+ return FALSE;
}
+ nm_active_connection_set_master (active, master_ac);
nm_log_dbg (LOGD_CORE, "Activation of '%s' depends on active connection %s",
nm_connection_get_id (connection),
nm_active_connection_get_path (master_ac));
}
- ac = internal_activate_device (manager,
- device,
- connection,
- specific_object,
- dbus_sender ? TRUE : FALSE,
- dbus_sender ? sender_uid : 0,
- dbus_sender,
- FALSE,
- master_ac,
- error);
+ /* Tear down any existing connection */
+ if (nm_device_get_act_request (device)) {
+ nm_log_info (LOGD_DEVICE, "(%s): disconnecting for new activation request.",
+ nm_device_get_iface (device));
+ nm_device_state_changed (device,
+ NM_DEVICE_STATE_DISCONNECTED,
+ NM_DEVICE_STATE_REASON_NONE);
+ }
+
+ /* Start the new activation */
+ nm_device_activate (device, NM_ACT_REQUEST (active));
+ return TRUE;
+}
-activated:
- if (ac)
- active_connection_add (manager, ac);
+static gboolean
+_internal_activate_generic (NMManager *self, NMActiveConnection *active, GError **error)
+{
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ gboolean success = FALSE;
- return ac;
+ if (NM_IS_VPN_CONNECTION (active))
+ success = _internal_activate_vpn (self, active, error);
+ else
+ success = _internal_activate_device (self, active, error);
+
+ if (success) {
+ nm_active_connection_export (active);
+ g_object_notify (G_OBJECT (self), NM_MANAGER_ACTIVE_CONNECTIONS);
+
+ /* Force an update of the Manager's activating-connection property.
+ * The device changes state before the AC gets exported, which causes
+ * the manager's 'activating-connection' property to be NULL since the
+ * AC only gets a D-Bus path when it's exported. So now that the AC
+ * is exported, make sure the manager's activating-connection property
+ * is up-to-date.
+ */
+ policy_activating_device_changed (G_OBJECT (priv->policy), NULL, self);
+ }
+
+ return success;
}
-/*
- * TODO this function was created and named in the era of user settings, where
- * we could get activation requests for a connection before we got the settings
- * data of that connection. Now that user settings are gone, flatten or rename
- * it.
- */
-static void
-pending_activate (NMManager *self, PendingActivation *pending)
+static NMActiveConnection *
+_new_vpn_active_connection (NMManager *self,
+ NMConnection *connection,
+ const char *specific_object,
+ NMAuthSubject *subject,
+ GError **error)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
- NMSettingsConnection *connection;
- NMActiveConnection *ac = NULL;
- GError *error = NULL;
- char *sender = NULL;
+ NMActiveConnection *parent = NULL;
+ NMDevice *device = NULL;
- /* Ok, we're authorized */
+ if (specific_object) {
+ /* Find the specifc connection the client requested we use */
+ parent = active_connection_get_by_path (self, specific_object);
+ if (!parent) {
+ g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
+ "Base connection for VPN connection not active.");
+ return NULL;
+ }
+ } else
+ parent = priv->primary_connection;
- connection = nm_settings_get_connection_by_path (priv->settings, pending->connection_path);
- if (!connection) {
- error = g_error_new_literal (NM_MANAGER_ERROR,
- NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
- "Connection could not be found.");
- goto out;
+ if (!parent) {
+ g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
+ "Could not find source connection.");
+ return NULL;
}
- if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr,
- pending->context,
- &sender,
- NULL)) {
- error = g_error_new_literal (NM_MANAGER_ERROR,
- NM_MANAGER_ERROR_PERMISSION_DENIED,
- "D-Bus sendder could not be determined.");
- goto out;
+ device = nm_active_connection_get_device (parent);
+ if (!device) {
+ g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "Source connection had no active device.");
+ return NULL;
}
- g_assert (sender);
- ac = nm_manager_activate_connection (self,
- NM_CONNECTION (connection),
- pending->specific_object_path,
- pending->device_path,
- sender,
- &error);
- g_free (sender);
+ return (NMActiveConnection *) nm_vpn_connection_new (connection,
+ device,
+ nm_active_connection_get_path (parent),
+ subject);
+}
- if (!ac) {
- nm_log_warn (LOGD_CORE, "connection %s failed to activate: (%d) %s",
- pending->connection_path,
- error ? error->code : -1,
- error && error->message ? error->message : "(unknown)");
+static NMActiveConnection *
+_new_active_connection (NMManager *self,
+ NMConnection *connection,
+ const char *specific_object,
+ NMDevice *device,
+ NMAuthSubject *subject,
+ GError **error)
+{
+ g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL);
+
+ /* Normalize the specific object */
+ if (specific_object && g_strcmp0 (specific_object, "/") == 0)
+ specific_object = NULL;
+
+ if (nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME)) {
+ return _new_vpn_active_connection (self,
+ connection,
+ specific_object,
+ subject,
+ error);
}
-out:
- pending_activation_destroy (pending, error, ac);
- g_clear_error (&error);
+ return (NMActiveConnection *) nm_act_request_new (connection,
+ specific_object,
+ subject,
+ device);
}
static void
-activation_auth_done (PendingActivation *pending, GError *error)
+_internal_activation_auth_done (NMActiveConnection *active,
+ gboolean success,
+ const char *error_desc,
+ gpointer user_data1,
+ gpointer user_data2)
{
- if (error)
- pending_activation_destroy (pending, error, NULL);
- else
- pending_activate (pending->manager, pending);
+ NMManager *self = user_data1;
+ GError *error = NULL;
+
+ if (success) {
+ if (_internal_activate_generic (self, active, &error))
+ return;
+ g_assert (error);
+ }
+
+ active_connection_remove (self, active);
+ nm_log_warn (LOGD_CORE, "Failed to activate '%s': %s",
+ nm_connection_get_id (nm_active_connection_get_connection (active)),
+ error_desc ? error_desc : error->message);
+ g_clear_error (&error);
+}
+
+NMActiveConnection *
+nm_manager_activate_connection (NMManager *self,
+ NMConnection *connection,
+ const char *specific_object,
+ NMDevice *device,
+ NMAuthSubject *subject,
+ GError **error)
+{
+ NMManagerPrivate *priv;
+ NMActiveConnection *active;
+
+ g_return_val_if_fail (self != NULL, NULL);
+ g_return_val_if_fail (connection != NULL, NULL);
+ g_return_val_if_fail (error != NULL, NULL);
+ g_return_val_if_fail (*error == NULL, NULL);
+
+ priv = NM_MANAGER_GET_PRIVATE (self);
+
+ active = _new_active_connection (self,
+ connection,
+ specific_object,
+ device,
+ subject,
+ error);
+ if (active) {
+ nm_active_connection_authorize (active, _internal_activation_auth_done, self, NULL);
+ active_connection_add (self, active);
+ }
+ return active;
+}
+
+static NMAuthSubject *
+validate_activation_request (NMManager *self,
+ DBusGMethodInvocation *context,
+ NMConnection *connection,
+ const char *device_path,
+ NMDevice **out_device,
+ gboolean *out_vpn,
+ GError **error)
+{
+ NMDevice *device = NULL;
+ gboolean vpn = FALSE;
+ NMAuthSubject *subject = NULL;
+
+ g_assert (connection);
+ g_assert (out_device);
+ g_assert (out_vpn);
+
+ /* Validate the caller */
+ subject = nm_auth_subject_new_from_context (context);
+ if (!subject) {
+ g_set_error_literal (error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_PERMISSION_DENIED,
+ "Failed to get request UID.");
+ return NULL;
+ }
+
+ /* Check whether it's a VPN or not */
+ if ( nm_connection_get_setting_vpn (connection)
+ || nm_connection_is_type (connection, NM_SETTING_VPN_SETTING_NAME))
+ vpn = TRUE;
+
+ /* Normalize device path */
+ if (device_path && g_strcmp0 (device_path, "/") == 0)
+ device_path = NULL;
+
+ /* And validate it */
+ if (device_path) {
+ device = nm_manager_get_device_by_path (self, device_path);
+ if (!device) {
+ g_set_error_literal (error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "Device not found");
+ goto error;
+ }
+ } else {
+ gboolean is_software = connection_needs_virtual_device (connection);
+
+ /* VPN and software-device connections don't need a device yet */
+ if (!vpn && !is_software) {
+ g_set_error_literal (error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "This connection requires an existing device.");
+ goto error;
+ }
+
+ if (is_software) {
+ /* Look for an existing device with the connection's interface name */
+ char *iface;
+
+ iface = get_virtual_iface_name (self, connection, NULL);
+ if (!iface) {
+ g_set_error_literal (error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "Failed to determine connection's virtual interface name");
+ goto error;
+ }
+
+ device = find_device_by_ip_iface (self, iface);
+ g_free (iface);
+ }
+ }
+
+ *out_device = device;
+ *out_vpn = vpn;
+ return subject;
+
+error:
+ g_object_unref (subject);
+ return NULL;
+}
+
+/***********************************************************************/
+
+static void
+activation_auth_done (NMActiveConnection *active,
+ gboolean success,
+ const char *error_desc,
+ gpointer user_data1,
+ gpointer user_data2)
+{
+ NMManager *self = user_data1;
+ DBusGMethodInvocation *context = user_data2;
+ GError *error = NULL;
+
+ if (success) {
+ if (_internal_activate_generic (self, active, &error)) {
+ dbus_g_method_return (context, nm_active_connection_get_path (active));
+ return;
+ }
+ } else {
+ error = g_error_new_literal (NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_PERMISSION_DENIED,
+ error_desc);
+ }
+
+ active_connection_remove (self, active);
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
}
static void
@@ -3295,64 +3102,129 @@ impl_manager_activate_connection (NMManager *self,
const char *specific_object_path,
DBusGMethodInvocation *context)
{
- PendingActivation *pending;
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ NMActiveConnection *active = NULL;
+ NMAuthSubject *subject = NULL;
+ NMConnection *connection;
+ NMDevice *device = NULL;
+ gboolean is_vpn = FALSE;
GError *error = NULL;
- /* Need to check the caller's permissions and stuff before we can
- * activate the connection.
- */
- pending = pending_activation_new (self,
- context,
- device_path,
- connection_path,
- NULL,
- specific_object_path,
- activation_auth_done,
- &error);
- if (pending)
- pending_activation_check_authorized (pending);
- else {
- g_assert (error);
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- }
+ connection = (NMConnection *) nm_settings_get_connection_by_path (priv->settings, connection_path);
+ if (!connection) {
+ error = g_error_new_literal (NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
+ "Connection could not be found.");
+ goto error;
+ }
+
+ subject = validate_activation_request (self,
+ context,
+ connection,
+ device_path,
+ &device,
+ &is_vpn,
+ &error);
+ if (!subject)
+ goto error;
+
+ active = _new_active_connection (self,
+ connection,
+ specific_object_path,
+ device,
+ subject,
+ &error);
+ if (!active)
+ goto error;
+
+ nm_active_connection_authorize (active, activation_auth_done, self, context);
+ active_connection_add (self, active);
+ g_clear_object (&subject);
+ return;
+
+error:
+ g_clear_object (&active);
+ g_clear_object (&subject);
+
+ g_assert (error);
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
}
+/***********************************************************************/
+
+typedef struct {
+ NMManager *manager;
+ NMActiveConnection *active;
+} AddAndActivateInfo;
+
static void
activation_add_done (NMSettings *self,
- NMSettingsConnection *connection,
+ NMSettingsConnection *new_connection,
GError *error,
DBusGMethodInvocation *context,
gpointer user_data)
{
- PendingActivation *pending = user_data;
+ AddAndActivateInfo *info = user_data;
+ GError *local = NULL;
- if (error)
- pending_activation_destroy (pending, error, NULL);
- else {
- /* Save the new connection's D-Bus path */
- pending->connection_path = g_strdup (nm_connection_get_path (NM_CONNECTION (connection)));
+ if (!error) {
+ nm_active_connection_set_connection (info->active, NM_CONNECTION (new_connection));
- /* And activate it */
- pending_activate (pending->manager, pending);
+ if (_internal_activate_generic (info->manager, info->active, &local)) {
+ dbus_g_method_return (context,
+ nm_connection_get_path (NM_CONNECTION (new_connection)),
+ nm_active_connection_get_path (info->active));
+ goto done;
+ }
+ error = local;
}
+
+ active_connection_remove (info->manager, info->active);
+
+ if (error)
+ dbus_g_method_return_error (context, error);
+ g_clear_error (&local);
+
+done:
+ g_object_unref (info->active);
+ g_free (info);
}
static void
-add_and_activate_auth_done (PendingActivation *pending, GError *error)
+add_and_activate_auth_done (NMActiveConnection *active,
+ gboolean success,
+ const char *error_desc,
+ gpointer user_data1,
+ gpointer user_data2)
{
- if (error)
- pending_activation_destroy (pending, error, NULL);
- else {
- NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (pending->manager);
+ NMManager *self = user_data1;
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ DBusGMethodInvocation *context = user_data2;
+ AddAndActivateInfo *info;
+ GError *error = NULL;
+
+ if (success) {
+ info = g_malloc0 (sizeof (*info));
+ info->manager = self;
+ info->active = g_object_ref (active);
/* Basic sender auth checks performed; try to add the connection */
nm_settings_add_connection_dbus (priv->settings,
- pending->connection,
+ nm_active_connection_get_connection (active),
TRUE,
- pending->context,
+ context,
activation_add_done,
- pending);
+ info);
+ } else {
+ active_connection_remove (self, active);
+
+ g_assert (error_desc);
+ error = g_error_new_literal (NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_PERMISSION_DENIED,
+ error_desc);
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
}
}
@@ -3363,29 +3235,99 @@ impl_manager_add_and_activate_connection (NMManager *self,
const char *specific_object_path,
DBusGMethodInvocation *context)
{
- PendingActivation *pending;
+ NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ NMConnection *connection = NULL;
+ GSList *all_connections = NULL;
+ NMActiveConnection *active;
+ NMAuthSubject *subject = NULL;
GError *error = NULL;
+ NMDevice *device = NULL;
+ gboolean vpn = FALSE;
- /* Need to check the caller's permissions and stuff before we can
- * activate the connection.
- */
- pending = pending_activation_new (self,
- context,
- device_path,
- NULL,
- settings,
- specific_object_path,
- add_and_activate_auth_done,
- &error);
- if (pending)
- pending_activation_check_authorized (pending);
- else {
- g_assert (error);
- dbus_g_method_return_error (context, error);
- g_error_free (error);
+ if (!settings || !g_hash_table_size (settings)) {
+ error = g_error_new_literal (NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_CONNECTION,
+ "Settings required to create a connection.");
+ goto error;
}
+
+ /* Try to create a new connection with the given settings */
+ connection = nm_connection_new ();
+ nm_connection_replace_settings (connection, settings, NULL);
+
+ subject = validate_activation_request (self,
+ context,
+ connection,
+ device_path,
+ &device,
+ &vpn,
+ &error);
+ if (!subject)
+ goto error;
+
+ /* AddAndActivate() requires a device to complete the connection with */
+ if (!device) {
+ error = g_error_new_literal (NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNKNOWN_DEVICE,
+ "This connection requires an existing device.");
+ goto error;
+ }
+
+ all_connections = nm_settings_get_connections (priv->settings);
+ if (vpn) {
+ /* Try to fill the VPN's connection setting and name at least */
+ if (!nm_connection_get_setting_vpn (connection)) {
+ error = g_error_new_literal (NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_UNSUPPORTED_CONNECTION_TYPE,
+ "VPN connections require a 'vpn' setting");
+ goto error;
+ }
+
+ nm_utils_complete_generic (connection,
+ NM_SETTING_VPN_SETTING_NAME,
+ all_connections,
+ _("VPN connection %d"),
+ NULL,
+ FALSE); /* No IPv6 by default for now */
+ } else {
+ /* Let each device subclass complete the connection */
+ if (!nm_device_complete_connection (device,
+ connection,
+ specific_object_path,
+ all_connections,
+ &error))
+ goto error;
+ }
+ g_slist_free (all_connections);
+ all_connections = NULL;
+
+ active = _new_active_connection (self,
+ connection,
+ specific_object_path,
+ device,
+ subject,
+ &error);
+ if (!active)
+ goto error;
+
+ nm_active_connection_authorize (active, add_and_activate_auth_done, self, context);
+ active_connection_add (self, active);
+ g_object_unref (connection);
+ g_object_unref (subject);
+ return;
+
+error:
+ g_clear_object (&connection);
+ g_slist_free (all_connections);
+ g_clear_object (&subject);
+ g_clear_object (&active);
+
+ g_assert (error);
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
}
+/***********************************************************************/
+
gboolean
nm_manager_deactivate_connection (NMManager *manager,
const char *connection_path,
@@ -3439,6 +3381,8 @@ deactivate_net_auth_done_cb (NMAuthChain *chain,
GError *error = NULL;
NMAuthCallResult result;
+ g_assert (context);
+
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL);
@@ -3481,7 +3425,6 @@ impl_manager_deactivate_connection (NMManager *self,
GError *error = NULL;
GSList *iter;
NMAuthChain *chain;
- const char *error_desc = NULL;
/* Find the connection by its object path */
for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) {
@@ -3497,25 +3440,26 @@ impl_manager_deactivate_connection (NMManager *self,
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_CONNECTION_NOT_ACTIVE,
"The connection was not active.");
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return;
+ goto done;
}
/* Validate the user request */
- chain = nm_auth_chain_new (context, deactivate_net_auth_done_cb, self, &error_desc);
- if (chain) {
- priv->auth_chains = g_slist_append (priv->auth_chains, chain);
-
- nm_auth_chain_set_data (chain, "path", g_strdup (active_path), g_free);
- nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
- } else {
+ chain = nm_auth_chain_new_context (context, deactivate_net_auth_done_cb, self);
+ if (!chain) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
- error_desc);
- dbus_g_method_return_error (context, error);
- g_error_free (error);
+ "Unable to authenticate request.");
+ goto done;
}
+
+ priv->auth_chains = g_slist_append (priv->auth_chains, chain);
+ nm_auth_chain_set_data (chain, "path", g_strdup (active_path), g_free);
+ nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
+
+done:
+ if (error)
+ dbus_g_method_return_error (context, error);
+ g_clear_error (&error);
}
/*
@@ -3775,6 +3719,8 @@ enable_net_done_cb (NMAuthChain *chain,
NMAuthCallResult result;
gboolean enable;
+ g_assert (context);
+
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK);
@@ -3811,7 +3757,6 @@ impl_manager_enable (NMManager *self,
NMManagerPrivate *priv;
NMAuthChain *chain;
GError *error = NULL;
- const char *error_desc;
g_return_if_fail (NM_IS_MANAGER (self));
@@ -3821,24 +3766,25 @@ impl_manager_enable (NMManager *self,
error = g_error_new (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_ALREADY_ENABLED_OR_DISABLED,
"Already %s", enable ? "enabled" : "disabled");
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return;
+ goto done;
}
- chain = nm_auth_chain_new (context, enable_net_done_cb, self, &error_desc);
- if (chain) {
- priv->auth_chains = g_slist_append (priv->auth_chains, chain);
-
- nm_auth_chain_set_data (chain, "enable", GUINT_TO_POINTER (enable), NULL);
- nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK, TRUE);
- } else {
+ chain = nm_auth_chain_new_context (context, enable_net_done_cb, self);
+ if (!chain) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
- error_desc);
- dbus_g_method_return_error (context, error);
- g_error_free (error);
+ "Unable to authenticate request.");
+ goto done;
}
+
+ priv->auth_chains = g_slist_append (priv->auth_chains, chain);
+ nm_auth_chain_set_data (chain, "enable", GUINT_TO_POINTER (enable), NULL);
+ nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK, TRUE);
+
+done:
+ if (error)
+ dbus_g_method_return_error (context, error);
+ g_clear_error (&error);
}
/* Permissions */
@@ -3871,6 +3817,8 @@ get_permissions_done_cb (NMAuthChain *chain,
GError *ret_error;
GHashTable *results;
+ g_assert (context);
+
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
if (error) {
nm_log_dbg (LOGD_CORE, "Permissions request failed: %s", error->message);
@@ -3908,31 +3856,30 @@ impl_manager_get_permissions (NMManager *self,
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMAuthChain *chain;
- const char *error_desc = NULL;
- GError *error;
-
- chain = nm_auth_chain_new (context, get_permissions_done_cb, self, &error_desc);
- if (chain) {
- priv->auth_chains = g_slist_append (priv->auth_chains, chain);
+ GError *error = NULL;
- nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK, FALSE);
- nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SLEEP_WAKE, FALSE);
- nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI, FALSE);
- nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN, FALSE);
- nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX, FALSE);
- nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, FALSE);
- nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE);
- nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE);
- nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM, FALSE);
- nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN, FALSE);
- nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, FALSE);
- } else {
+ chain = nm_auth_chain_new_context (context, get_permissions_done_cb, self);
+ if (!chain) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
- error_desc);
+ "Unable to authenticate request.");
dbus_g_method_return_error (context, error);
- g_error_free (error);
+ g_clear_error (&error);
+ return;
}
+
+ priv->auth_chains = g_slist_append (priv->auth_chains, chain);
+ nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_NETWORK, FALSE);
+ nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SLEEP_WAKE, FALSE);
+ nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIFI, FALSE);
+ nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WWAN, FALSE);
+ nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_ENABLE_DISABLE_WIMAX, FALSE);
+ nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, FALSE);
+ nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE);
+ nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_OPEN, FALSE);
+ nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM, FALSE);
+ nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_OWN, FALSE);
+ nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, FALSE);
}
static gboolean
@@ -4033,22 +3980,21 @@ impl_manager_check_connectivity (NMManager *manager,
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
NMAuthChain *chain;
- const char *error_desc = NULL;
- GError *error;
-
- /* Validate the user request */
- chain = nm_auth_chain_new (context, check_connectivity_auth_done_cb, manager, &error_desc);
- if (chain) {
- priv->auth_chains = g_slist_append (priv->auth_chains, chain);
+ GError *error = NULL;
- nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
- } else {
+ /* Validate the request */
+ chain = nm_auth_chain_new_context (context, check_connectivity_auth_done_cb, manager);
+ if (!chain) {
error = g_error_new_literal (NM_MANAGER_ERROR,
NM_MANAGER_ERROR_PERMISSION_DENIED,
- error_desc);
+ "Unable to authenticate request.");
dbus_g_method_return_error (context, error);
- g_error_free (error);
+ g_clear_error (&error);
+ return;
}
+
+ priv->auth_chains = g_slist_append (priv->auth_chains, chain);
+ nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_NETWORK_CONTROL, TRUE);
}
void
@@ -4304,9 +4250,9 @@ prop_filter (DBusConnection *connection,
const char *propiface = NULL;
const char *propname = NULL;
const char *glib_propname = NULL, *permission = NULL;
- gulong caller_uid = G_MAXULONG;
DBusMessage *reply = NULL;
gboolean set_enabled = FALSE;
+ NMAuthSubject *subject = NULL;
NMAuthChain *chain;
GObject *obj;
@@ -4366,19 +4312,21 @@ prop_filter (DBusConnection *connection,
goto out;
}
- if (!nm_dbus_manager_get_caller_info_from_message (priv->dbus_mgr,
- connection,
- message,
- NULL,
- &caller_uid)) {
+ subject = nm_auth_subject_new_from_message (connection, message);\
+ if (!subject) {
reply = dbus_message_new_error (message, NM_PERM_DENIED_ERROR,
"Could not determine request UID.");
goto out;
}
/* Validate the user request */
- chain = nm_auth_chain_new_raw_message (message, caller_uid, prop_set_auth_done_cb, self);
- g_assert (chain);
+ chain = nm_auth_chain_new_subject (subject, NULL, prop_set_auth_done_cb, self);
+ if (!chain) {
+ reply = dbus_message_new_error (message, NM_PERM_DENIED_ERROR,
+ "Could not authenticate request.");
+ goto out;
+ }
+
priv->auth_chains = g_slist_append (priv->auth_chains, chain);
nm_auth_chain_set_data (chain, "prop", g_strdup (glib_propname), g_free);
nm_auth_chain_set_data (chain, "permission", g_strdup (permission), g_free);
@@ -4393,6 +4341,8 @@ out:
dbus_connection_send (connection, reply, NULL);
dbus_message_unref (reply);
}
+ g_clear_object (&subject);
+
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -4537,7 +4487,6 @@ dispose (GObject *object)
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
DBusGConnection *bus;
DBusConnection *dbus_connection;
- GSList *iter;
if (priv->disposed) {
G_OBJECT_CLASS (nm_manager_parent_class)->dispose (object);
@@ -4561,8 +4510,8 @@ dispose (GObject *object)
priv->ac_cleanup_id = 0;
}
- for (iter = priv->active_connections; iter; iter = g_slist_next (iter))
- active_connection_removed (manager, NM_ACTIVE_CONNECTION (iter->data));
+ while (priv->active_connections)
+ active_connection_remove (manager, NM_ACTIVE_CONNECTION (priv->active_connections->data));
g_slist_free (priv->active_connections);
priv->active_connections = NULL;
g_clear_object (&priv->primary_connection);
@@ -4812,7 +4761,8 @@ get_property (GObject *object, guint prop_id,
active = g_ptr_array_sized_new (3);
for (iter = priv->active_connections; iter; iter = g_slist_next (iter)) {
path = nm_active_connection_get_path (NM_ACTIVE_CONNECTION (iter->data));
- g_ptr_array_add (active, g_strdup (path));
+ if (path)
+ g_ptr_array_add (active, g_strdup (path));
}
g_value_take_boxed (value, active);
break;
@@ -4820,12 +4770,12 @@ get_property (GObject *object, guint prop_id,
g_value_set_uint (value, nm_connectivity_get_state (priv->connectivity));
break;
case PROP_PRIMARY_CONNECTION:
- path = priv->primary_connection ? nm_active_connection_get_path (priv->primary_connection) : "/";
- g_value_set_boxed (value, path);
+ path = priv->primary_connection ? nm_active_connection_get_path (priv->primary_connection) : NULL;
+ g_value_set_boxed (value, path ? path : "/");
break;
case PROP_ACTIVATING_CONNECTION:
- path = priv->activating_connection ? nm_active_connection_get_path (priv->activating_connection) : "/";
- g_value_set_boxed (value, path);
+ path = priv->activating_connection ? nm_active_connection_get_path (priv->activating_connection) : NULL;
+ g_value_set_boxed (value, path ? path : "/");
break;
case PROP_HOSTNAME:
g_value_set_string (value, priv->hostname);
diff --git a/src/nm-manager.h b/src/nm-manager.h
index fd6fa0aeee..5f848688d9 100644
--- a/src/nm-manager.h
+++ b/src/nm-manager.h
@@ -27,6 +27,7 @@
#include <dbus/dbus-glib.h>
#include "nm-device.h"
#include "nm-settings.h"
+#include "nm-auth-subject.h"
#define NM_TYPE_MANAGER (nm_manager_get_type ())
#define NM_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_MANAGER, NMManager))
@@ -116,8 +117,8 @@ NMDevice *nm_manager_get_device_by_ifindex (NMManager *manager,
NMActiveConnection *nm_manager_activate_connection (NMManager *manager,
NMConnection *connection,
const char *specific_object,
- const char *device_path,
- const char *dbus_sender, /* NULL if automatic */
+ NMDevice *device,
+ NMAuthSubject *subject,
GError **error);
gboolean nm_manager_deactivate_connection (NMManager *manager,
diff --git a/src/nm-policy.c b/src/nm-policy.c
index 49c005c47e..98818047c0 100644
--- a/src/nm-policy.c
+++ b/src/nm-policy.c
@@ -669,7 +669,7 @@ update_ip4_routing (NMPolicy *policy, gboolean force_update)
gw_addr = nm_ip4_config_get_gateway (ip4_config);
if (vpn) {
- NMDevice *parent = nm_vpn_connection_get_parent_device (vpn);
+ NMDevice *parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
int parent_ifindex = nm_device_get_ip_ifindex (parent);
NMIP4Config *parent_ip4 = nm_device_get_ip4_config (parent);
guint32 parent_mss = parent_ip4 ? nm_ip4_config_get_mss (parent_ip4) : 0;
@@ -683,7 +683,7 @@ update_ip4_routing (NMPolicy *policy, gboolean force_update)
}
}
- default_device = nm_vpn_connection_get_parent_device (vpn);
+ default_device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
} else {
int mss = nm_ip4_config_get_mss (ip4_config);
@@ -856,7 +856,7 @@ update_ip6_routing (NMPolicy *policy, gboolean force_update)
gw_addr = &in6addr_any;
if (vpn) {
- NMDevice *parent = nm_vpn_connection_get_parent_device (vpn);
+ NMDevice *parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
int parent_ifindex = nm_device_get_ip_ifindex (parent);
NMIP6Config *parent_ip6 = nm_device_get_ip6_config (parent);
guint32 parent_mss = parent_ip6 ? nm_ip6_config_get_mss (parent_ip6) : 0;
@@ -873,7 +873,7 @@ update_ip6_routing (NMPolicy *policy, gboolean force_update)
}
}
- default_device6 = nm_vpn_connection_get_parent_device (vpn);
+ default_device6 = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
} else {
int mss = nm_ip6_config_get_mss (ip6_config);
@@ -1034,14 +1034,16 @@ auto_activate_device (gpointer user_data)
best_connection = nm_device_get_best_auto_connection (data->device, connections, &specific_object);
if (best_connection) {
GError *error = NULL;
+ NMAuthSubject *subject;
nm_log_info (LOGD_DEVICE, "Auto-activating connection '%s'.",
nm_connection_get_id (best_connection));
+ subject = nm_auth_subject_new_internal ();
if (!nm_manager_activate_connection (priv->manager,
best_connection,
specific_object,
- nm_device_get_path (data->device),
- NULL,
+ data->device,
+ subject,
&error)) {
nm_log_info (LOGD_DEVICE, "Connection '%s' auto-activation failed: (%d) %s",
nm_connection_get_id (best_connection),
@@ -1049,6 +1051,7 @@ auto_activate_device (gpointer user_data)
error ? error->message : "(none)");
g_error_free (error);
}
+ g_object_unref (subject);
}
g_slist_free (connections);
@@ -1110,7 +1113,7 @@ static void
pending_secondary_data_free (PendingSecondaryData *data)
{
g_object_unref (data->device);
- g_slist_free_full (data->secondaries, g_free);
+ g_slist_free_full (data->secondaries, g_object_unref);
memset (data, 0, sizeof (*data));
g_free (data);
}
@@ -1121,51 +1124,47 @@ process_secondaries (NMPolicy *policy,
gboolean connected)
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy);
- NMDevice *device = NULL;
- const char *ac_path;
GSList *iter, *iter2;
- nm_log_dbg (LOGD_DEVICE, "Secondary connection '%s' %s; active path '%s'",
- nm_active_connection_get_name (active),
- connected ? "SUCCEEDED" : "FAILED",
- nm_active_connection_get_path (active));
-
- ac_path = nm_active_connection_get_path (active);
-
- if (NM_IS_VPN_CONNECTION (active))
- device = nm_vpn_connection_get_parent_device (NM_VPN_CONNECTION (active));
-
+ /* Loop through devices waiting for secondary connections to activate */
for (iter = priv->pending_secondaries; iter; iter = g_slist_next (iter)) {
PendingSecondaryData *secondary_data = (PendingSecondaryData *) iter->data;
NMDevice *item_device = secondary_data->device;
- if (!device || item_device == device) {
- for (iter2 = secondary_data->secondaries; iter2; iter2 = g_slist_next (iter2)) {
- char *list_ac_path = (char *) iter2->data;
-
- if (g_strcmp0 (ac_path, list_ac_path) == 0) {
- if (connected) {
- /* Secondary connection activated */
- secondary_data->secondaries = g_slist_remove (secondary_data->secondaries, list_ac_path);
- g_free (list_ac_path);
- if (!secondary_data->secondaries) {
- /* None secondary UUID remained -> remove the secondary data item */
- priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data);
- pending_secondary_data_free (secondary_data);
- nm_device_state_changed (item_device, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_REASON_NONE);
- return;
- }
- } else {
- /* Secondary connection failed -> do not watch other connections */
- priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data);
- pending_secondary_data_free (secondary_data);
- nm_device_state_changed (item_device, NM_DEVICE_STATE_FAILED,
- NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED);
- return;
- }
+ /* Look for 'active' in each device's secondary connections list */
+ for (iter2 = secondary_data->secondaries; iter2; iter2 = g_slist_next (iter2)) {
+ NMActiveConnection *secondary_active = NM_ACTIVE_CONNECTION (iter2->data);
+
+ if (active != secondary_active)
+ continue;
+
+ if (connected) {
+ nm_log_dbg (LOGD_DEVICE, "Secondary connection '%s' SUCCEEDED; active path '%s'",
+ nm_active_connection_get_name (active),
+ nm_active_connection_get_path (active));
+
+ /* Secondary connection activated */
+ secondary_data->secondaries = g_slist_remove (secondary_data->secondaries, secondary_active);
+ g_object_unref (secondary_active);
+ if (!secondary_data->secondaries) {
+ /* No secondary UUID remained -> remove the secondary data item */
+ priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data);
+ pending_secondary_data_free (secondary_data);
+ nm_device_state_changed (item_device, NM_DEVICE_STATE_ACTIVATED, NM_DEVICE_STATE_REASON_NONE);
+ break;
}
+ } else {
+ nm_log_dbg (LOGD_DEVICE, "Secondary connection '%s' FAILED; active path '%s'",
+ nm_active_connection_get_name (active),
+ nm_active_connection_get_path (active));
+
+ /* Secondary connection failed -> do not watch other connections */
+ priv->pending_secondaries = g_slist_remove (priv->pending_secondaries, secondary_data);
+ pending_secondary_data_free (secondary_data);
+ nm_device_state_changed (item_device, NM_DEVICE_STATE_FAILED,
+ NM_DEVICE_STATE_REASON_SECONDARY_CONNECTION_FAILED);
+ break;
}
- return;
}
}
}
@@ -1233,6 +1232,7 @@ schedule_activate_check (NMPolicy *policy, NMDevice *device, guint delay_seconds
{
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (policy);
ActivateData *data;
+ const GSList *active_connections, *iter;
if (nm_manager_get_state (priv->manager) == NM_STATE_ASLEEP)
return;
@@ -1246,6 +1246,15 @@ schedule_activate_check (NMPolicy *policy, NMDevice *device, guint delay_seconds
if (!nm_device_autoconnect_allowed (device))
return;
+ /* If the device already has an activation in-progress or waiting for
+ * authentication, don't start an auto-activation for it.
+ */
+ active_connections = nm_manager_get_active_connections (priv->manager);
+ for (iter = active_connections; iter; iter = iter->next) {
+ if (nm_active_connection_get_device (NM_ACTIVE_CONNECTION (iter->data)) == device)
+ return;
+ }
+
/* Schedule an auto-activation if there isn't one already for this device */
if (find_pending_activation (priv->pending_activation_checks, device) == NULL) {
data = activate_data_new (policy, device, delay_seconds);
@@ -1357,13 +1366,12 @@ activate_secondary_connections (NMPolicy *policy,
ac = nm_manager_activate_connection (priv->manager,
NM_CONNECTION (settings_con),
nm_active_connection_get_path (NM_ACTIVE_CONNECTION (req)),
- nm_device_get_path (device),
- nm_act_request_get_dbus_sender (req),
+ device,
+ nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (req)),
&error);
- if (ac) {
- secondary_ac_list = g_slist_append (secondary_ac_list,
- g_strdup (nm_active_connection_get_path (ac)));
- } else {
+ if (ac)
+ secondary_ac_list = g_slist_append (secondary_ac_list, g_object_ref (ac));
+ else {
nm_log_warn (LOGD_DEVICE, "Secondary connection '%s' auto-activation failed: (%d) %s",
sec_uuid,
error ? error->code : 0,
@@ -1384,7 +1392,7 @@ activate_secondary_connections (NMPolicy *policy,
secondary_data = pending_secondary_data_new (device, secondary_ac_list);
priv->pending_secondaries = g_slist_append (priv->pending_secondaries, secondary_data);
} else
- g_slist_free_full (secondary_ac_list, g_free);
+ g_slist_free_full (secondary_ac_list, g_object_unref);
return success;
}
@@ -1720,8 +1728,6 @@ vpn_connection_activated (NMPolicy *policy, NMVPNConnection *vpn)
update_routing_and_dns (policy, TRUE);
nm_dns_manager_end_updates (mgr, __func__);
-
- process_secondaries (policy, NM_ACTIVE_CONNECTION (vpn), TRUE);
}
static void
@@ -1737,7 +1743,7 @@ vpn_connection_deactivated (NMPolicy *policy, NMVPNConnection *vpn)
nm_dns_manager_begin_updates (mgr, __func__);
ip_iface = nm_vpn_connection_get_ip_iface (vpn);
- parent = nm_vpn_connection_get_parent_device (vpn);
+ parent = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
ip4_config = nm_vpn_connection_get_ip4_config (vpn);
if (ip4_config) {
@@ -1754,8 +1760,23 @@ vpn_connection_deactivated (NMPolicy *policy, NMVPNConnection *vpn)
update_routing_and_dns (policy, TRUE);
nm_dns_manager_end_updates (mgr, __func__);
+}
- process_secondaries (policy, NM_ACTIVE_CONNECTION (vpn), FALSE);
+static void
+vpn_connection_state_changed (NMVPNConnection *vpn,
+ NMVPNConnectionState new_state,
+ NMVPNConnectionState old_state,
+ NMVPNConnectionStateReason reason,
+ NMPolicy *policy)
+{
+ if (new_state == NM_VPN_CONNECTION_STATE_ACTIVATED)
+ vpn_connection_activated (policy, vpn);
+ else if (new_state >= NM_VPN_CONNECTION_STATE_FAILED) {
+ /* Only clean up IP/DNS if the connection ever got past IP_CONFIG */
+ if (old_state >= NM_VPN_CONNECTION_STATE_IP_CONFIG_GET &&
+ old_state <= NM_VPN_CONNECTION_STATE_ACTIVATED)
+ vpn_connection_deactivated (policy, vpn);
+ }
}
static void
@@ -1763,18 +1784,12 @@ active_connection_state_changed (NMActiveConnection *active,
GParamSpec *pspec,
NMPolicy *policy)
{
- switch (nm_active_connection_get_state (active)) {
- case NM_ACTIVE_CONNECTION_STATE_ACTIVATED:
- if (NM_IS_VPN_CONNECTION (active))
- vpn_connection_activated (policy, NM_VPN_CONNECTION (active));
- break;
- case NM_ACTIVE_CONNECTION_STATE_DEACTIVATED:
- if (NM_IS_VPN_CONNECTION (active))
- vpn_connection_deactivated (policy, NM_VPN_CONNECTION (active));
- break;
- default:
- break;
- }
+ NMActiveConnectionState state = nm_active_connection_get_state (active);
+
+ if (state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED)
+ process_secondaries (policy, active, TRUE);
+ else if (state == NM_ACTIVE_CONNECTION_STATE_DEACTIVATED)
+ process_secondaries (policy, active, FALSE);
}
static void
@@ -1782,7 +1797,13 @@ active_connection_added (NMManager *manager,
NMActiveConnection *active,
gpointer user_data)
{
- NMPolicy *policy = (NMPolicy *) user_data;
+ NMPolicy *policy = NM_POLICY (user_data);
+
+ if (NM_IS_VPN_CONNECTION (active)) {
+ g_signal_connect (active, NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED,
+ G_CALLBACK (vpn_connection_state_changed),
+ policy);
+ }
g_signal_connect (active, "notify::" NM_ACTIVE_CONNECTION_STATE,
G_CALLBACK (active_connection_state_changed),
@@ -1794,9 +1815,14 @@ active_connection_removed (NMManager *manager,
NMActiveConnection *active,
gpointer user_data)
{
+ NMPolicy *policy = NM_POLICY (user_data);
+
+ g_signal_handlers_disconnect_by_func (active,
+ vpn_connection_state_changed,
+ policy);
g_signal_handlers_disconnect_by_func (active,
active_connection_state_changed,
- (NMPolicy *) user_data);
+ policy);
}
/**************************************************************************/
diff --git a/src/settings/nm-agent-manager.c b/src/settings/nm-agent-manager.c
index 5d1c519efa..33fbbe7ff3 100644
--- a/src/settings/nm-agent-manager.c
+++ b/src/settings/nm-agent-manager.c
@@ -206,6 +206,8 @@ agent_register_permissions_done (NMAuthChain *chain,
GHashTableIter iter;
Request *req;
+ g_assert (context);
+
priv->chains = g_slist_remove (priv->chains, chain);
if (error) {
@@ -270,22 +272,20 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self,
DBusGMethodInvocation *context)
{
NMAgentManagerPrivate *priv = NM_AGENT_MANAGER_GET_PRIVATE (self);
- char *sender = NULL;
+ NMAuthSubject *subject;
gulong sender_uid = G_MAXULONG;
GError *error = NULL, *local = NULL;
NMSecretAgent *agent;
NMAuthChain *chain;
- const char *error_desc = NULL;
- if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr,
- context,
- &sender,
- &sender_uid)) {
+ subject = nm_auth_subject_new_from_context (context);
+ if (!subject) {
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN,
"Unable to determine request sender and UID.");
goto done;
}
+ sender_uid = nm_auth_subject_get_uid (subject);
if ( 0 != sender_uid
&& !nm_session_monitor_uid_has_session (priv->session_monitor,
@@ -311,7 +311,7 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self,
}
/* Success, add the new agent */
- agent = nm_secret_agent_new (context, sender, identifier, sender_uid, capabilities);
+ agent = nm_secret_agent_new (context, subject, identifier, capabilities);
if (!agent) {
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
NM_AGENT_MANAGER_ERROR_INTERNAL_ERROR,
@@ -323,7 +323,7 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self,
nm_secret_agent_get_description (agent));
/* Kick off permissions requests for this agent */
- chain = nm_auth_chain_new (context, agent_register_permissions_done, self, &error_desc);
+ chain = nm_auth_chain_new_subject (subject, context, agent_register_permissions_done, self);
if (chain) {
nm_auth_chain_set_data (chain, "agent", agent, g_object_unref);
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_WIFI_SHARE_PROTECTED, FALSE);
@@ -333,7 +333,7 @@ impl_agent_manager_register_with_capabilities (NMAgentManager *self,
} else {
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN,
- error_desc);
+ "Unable to start agent authentication.");
}
done:
@@ -341,7 +341,7 @@ done:
dbus_g_method_return_error (context, error);
g_clear_error (&error);
g_clear_error (&local);
- g_free (sender);
+ g_clear_object (&subject);
}
static void
@@ -363,6 +363,7 @@ impl_agent_manager_unregister (NMAgentManager *self,
if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr,
context,
&sender,
+ NULL,
NULL)) {
error = g_error_new_literal (NM_AGENT_MANAGER_ERROR,
NM_AGENT_MANAGER_ERROR_SENDER_UNKNOWN,
@@ -1016,10 +1017,10 @@ get_next_cb (Request *parent)
nm_log_dbg (LOGD_AGENTS, "(%p/%s/%s) request has system secrets; checking agent %s for MODIFY",
req, parent->detail, req->setting_name, agent_dbus_owner);
- req->chain = nm_auth_chain_new_dbus_sender (agent_dbus_owner,
- nm_secret_agent_get_owner_uid (parent->current),
- get_agent_modify_auth_cb,
- req);
+ req->chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (parent->current),
+ NULL,
+ get_agent_modify_auth_cb,
+ req);
g_assert (req->chain);
/* If the caller is the only user in the connection's permissions, then
@@ -1502,10 +1503,10 @@ authority_changed_cb (gpointer user_data)
NMAuthChain *chain;
/* Kick off permissions requests for this agent */
- chain = nm_auth_chain_new_dbus_sender (nm_secret_agent_get_dbus_owner (agent),
- nm_secret_agent_get_owner_uid (agent),
- agent_permissions_changed_done,
- self);
+ chain = nm_auth_chain_new_subject (nm_secret_agent_get_subject (agent),
+ NULL,
+ agent_permissions_changed_done,
+ self);
g_assert (chain);
priv->chains = g_slist_append (priv->chains, chain);
diff --git a/src/settings/nm-secret-agent.c b/src/settings/nm-secret-agent.c
index 7f0e879a3a..66ddc36a2a 100644
--- a/src/settings/nm-secret-agent.c
+++ b/src/settings/nm-secret-agent.c
@@ -31,6 +31,7 @@
#include "nm-secret-agent.h"
#include "nm-dbus-manager.h"
#include "nm-dbus-glib-types.h"
+#include "nm-glib-compat.h"
#include "nm-logging.h"
G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT)
@@ -40,12 +41,9 @@ G_DEFINE_TYPE (NMSecretAgent, nm_secret_agent, G_TYPE_OBJECT)
NMSecretAgentPrivate))
typedef struct {
- gboolean disposed;
-
char *description;
- char *owner;
+ NMAuthSubject *subject;
char *identifier;
- uid_t owner_uid;
char *owner_username;
NMSecretAgentCapabilities capabilities;
guint32 hash;
@@ -106,10 +104,10 @@ nm_secret_agent_get_description (NMSecretAgent *agent)
priv = NM_SECRET_AGENT_GET_PRIVATE (agent);
if (!priv->description) {
- priv->description = g_strdup_printf ("%s/%s/%u",
- priv->owner,
+ priv->description = g_strdup_printf ("%s/%s/%lu",
+ nm_auth_subject_get_dbus_sender (priv->subject),
priv->identifier,
- priv->owner_uid);
+ nm_auth_subject_get_uid (priv->subject));
}
return priv->description;
@@ -120,7 +118,7 @@ nm_secret_agent_get_dbus_owner (NMSecretAgent *agent)
{
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL);
- return NM_SECRET_AGENT_GET_PRIVATE (agent)->owner;
+ return nm_auth_subject_get_dbus_sender (NM_SECRET_AGENT_GET_PRIVATE (agent)->subject);
}
const char *
@@ -131,16 +129,16 @@ nm_secret_agent_get_identifier (NMSecretAgent *agent)
return NM_SECRET_AGENT_GET_PRIVATE (agent)->identifier;
}
-uid_t
+gulong
nm_secret_agent_get_owner_uid (NMSecretAgent *agent)
{
- g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), G_MAXUINT);
+ g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), G_MAXULONG);
- return NM_SECRET_AGENT_GET_PRIVATE (agent)->owner_uid;
+ return nm_auth_subject_get_uid (NM_SECRET_AGENT_GET_PRIVATE (agent)->subject);
}
const char *
-nm_secret_agent_get_owner_username(NMSecretAgent *agent)
+nm_secret_agent_get_owner_username (NMSecretAgent *agent)
{
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL);
@@ -156,13 +154,21 @@ nm_secret_agent_get_capabilities (NMSecretAgent *agent)
}
guint32
-nm_secret_agent_get_hash (NMSecretAgent *agent)
+nm_secret_agent_get_hash (NMSecretAgent *agent)
{
g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), 0);
return NM_SECRET_AGENT_GET_PRIVATE (agent)->hash;
}
+NMAuthSubject *
+nm_secret_agent_get_subject (NMSecretAgent *agent)
+{
+ g_return_val_if_fail (NM_IS_SECRET_AGENT (agent), NULL);
+
+ return NM_SECRET_AGENT_GET_PRIVATE (agent)->subject;
+}
+
/**
* nm_secret_agent_add_permission:
* @agent: A #NMSecretAgent.
@@ -443,9 +449,8 @@ proxy_cleanup (NMSecretAgent *self)
NMSecretAgent *
nm_secret_agent_new (DBusGMethodInvocation *context,
- const char *owner,
+ NMAuthSubject *subject,
const char *identifier,
- uid_t owner_uid,
NMSecretAgentCapabilities capabilities)
{
NMSecretAgent *self;
@@ -453,10 +458,11 @@ nm_secret_agent_new (DBusGMethodInvocation *context,
char *hash_str, *username;
struct passwd *pw;
- g_return_val_if_fail (owner != NULL, NULL);
+ g_return_val_if_fail (context != NULL, NULL);
+ g_return_val_if_fail (NM_IS_AUTH_SUBJECT (subject), NULL);
g_return_val_if_fail (identifier != NULL, NULL);
- pw = getpwuid (owner_uid);
+ pw = getpwuid (nm_auth_subject_get_uid (subject));
g_return_val_if_fail (pw != NULL, NULL);
g_return_val_if_fail (pw->pw_name[0] != '\0', NULL);
username = g_strdup (pw->pw_name);
@@ -464,19 +470,18 @@ nm_secret_agent_new (DBusGMethodInvocation *context,
self = (NMSecretAgent *) g_object_new (NM_TYPE_SECRET_AGENT, NULL);
priv = NM_SECRET_AGENT_GET_PRIVATE (self);
- priv->owner = g_strdup (owner);
priv->identifier = g_strdup (identifier);
- priv->owner_uid = owner_uid;
priv->owner_username = g_strdup (username);
priv->capabilities = capabilities;
+ priv->subject = g_object_ref (subject);
- hash_str = g_strdup_printf ("%08u%s", owner_uid, identifier);
+ hash_str = g_strdup_printf ("%16lu%s", nm_auth_subject_get_uid (subject), identifier);
priv->hash = g_str_hash (hash_str);
g_free (hash_str);
priv->proxy = nm_dbus_manager_new_proxy (nm_dbus_manager_get (),
context,
- owner,
+ nm_auth_subject_get_dbus_sender (subject),
NM_DBUS_PATH_SECRET_AGENT,
NM_DBUS_INTERFACE_SECRET_AGENT);
g_assert (priv->proxy);
@@ -501,21 +506,21 @@ dispose (GObject *object)
{
NMSecretAgentPrivate *priv = NM_SECRET_AGENT_GET_PRIVATE (object);
- if (!priv->disposed) {
- priv->disposed = TRUE;
-
- g_free (priv->description);
- g_free (priv->owner);
- g_free (priv->identifier);
- g_free (priv->owner_username);
+ g_clear_pointer (&priv->description, g_free);
+ g_clear_pointer (&priv->identifier, g_free);
+ g_clear_pointer (&priv->owner_username, g_free);
- g_slist_free_full (priv->permissions, g_free);
+ g_slist_free_full (priv->permissions, g_free);
+ priv->permissions = NULL;
+ if (priv->requests) {
g_hash_table_destroy (priv->requests);
-
- proxy_cleanup (NM_SECRET_AGENT (object));
+ priv->requests = NULL;
}
+ proxy_cleanup (NM_SECRET_AGENT (object));
+ g_clear_object (&priv->subject);
+
G_OBJECT_CLASS (nm_secret_agent_parent_class)->dispose (object);
}
diff --git a/src/settings/nm-secret-agent.h b/src/settings/nm-secret-agent.h
index a59182e533..b75f7177db 100644
--- a/src/settings/nm-secret-agent.h
+++ b/src/settings/nm-secret-agent.h
@@ -29,6 +29,7 @@
#include <nm-connection.h>
#include "nm-dbus-manager.h"
#include "nm-settings-flags.h"
+#include "nm-auth-subject.h"
/* NOTE: ensure these capabilities match those in introspection/nm-secret-agent.xml and
* libnm-glib/nm-secret-agent.h.
@@ -56,9 +57,8 @@ typedef struct {
GType nm_secret_agent_get_type (void);
NMSecretAgent *nm_secret_agent_new (DBusGMethodInvocation *context,
- const char *owner,
+ NMAuthSubject *subject,
const char *identifier,
- uid_t owner_uid,
NMSecretAgentCapabilities capabilities);
const char *nm_secret_agent_get_description (NMSecretAgent *agent);
@@ -67,7 +67,7 @@ const char *nm_secret_agent_get_dbus_owner (NMSecretAgent *agent);
const char *nm_secret_agent_get_identifier (NMSecretAgent *agent);
-uid_t nm_secret_agent_get_owner_uid (NMSecretAgent *agent);
+gulong nm_secret_agent_get_owner_uid (NMSecretAgent *agent);
const char *nm_secret_agent_get_owner_username (NMSecretAgent *agent);
@@ -75,6 +75,8 @@ NMSecretAgentCapabilities nm_secret_agent_get_capabilities (NMSecretAgent *agent
guint32 nm_secret_agent_get_hash (NMSecretAgent *agent);
+NMAuthSubject *nm_secret_agent_get_subject (NMSecretAgent *agent);
+
void nm_secret_agent_add_permission (NMSecretAgent *agent,
const char *permission,
gboolean allowed);
diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c
index 0d7fe3a8e1..59b29ad199 100644
--- a/src/settings/nm-settings-connection.c
+++ b/src/settings/nm-settings-connection.c
@@ -994,47 +994,35 @@ pk_auth_cb (NMAuthChain *chain,
nm_auth_chain_unref (chain);
}
-static gboolean
-check_user_in_acl (NMConnection *connection,
- DBusGMethodInvocation *context,
- NMSessionMonitor *session_monitor,
- gulong *out_sender_uid,
- GError **error)
+/**
+ * _new_auth_subject:
+ * @context: the D-Bus method invocation context
+ * @error: on failure, a #GError
+ *
+ * Creates an NMAuthSubject for the caller.
+ *
+ * Returns: the #NMAuthSubject on success, or %NULL on failure and sets @error
+ */
+static NMAuthSubject *
+_new_auth_subject (DBusGMethodInvocation *context, GError **error)
{
- gulong sender_uid = G_MAXULONG;
- char *error_desc = NULL;
+ NMAuthSubject *subject;
- g_return_val_if_fail (connection != NULL, FALSE);
- g_return_val_if_fail (context != NULL, FALSE);
- g_return_val_if_fail (session_monitor != NULL, FALSE);
-
- /* Get the caller's UID */
- if (!nm_dbus_manager_get_caller_info (nm_dbus_manager_get (), context, NULL, &sender_uid)) {
+ subject = nm_auth_subject_new_from_context (context);
+ if (!subject) {
g_set_error_literal (error,
NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
"Unable to determine UID of request.");
- return FALSE;
}
- /* Make sure the UID can view this connection */
- if (!nm_auth_uid_in_acl (connection, session_monitor, sender_uid, &error_desc)) {
- g_set_error_literal (error,
- NM_SETTINGS_ERROR,
- NM_SETTINGS_ERROR_PERMISSION_DENIED,
- error_desc);
- g_free (error_desc);
- return FALSE;
- }
-
- if (out_sender_uid)
- *out_sender_uid = sender_uid;
- return TRUE;
+ return subject;
}
static void
auth_start (NMSettingsConnection *self,
DBusGMethodInvocation *context,
+ NMAuthSubject *subject,
const char *check_permission,
AuthCallback callback,
gpointer callback_data)
@@ -1043,41 +1031,49 @@ auth_start (NMSettingsConnection *self,
NMAuthChain *chain;
gulong sender_uid = G_MAXULONG;
GError *error = NULL;
- const char *error_desc = NULL;
+ char *error_desc = NULL;
+
+ g_return_if_fail (context != NULL);
+ g_return_if_fail (NM_IS_AUTH_SUBJECT (subject));
+
+ /* Ensure the caller can view this connection */
+ if (!nm_auth_uid_in_acl (NM_CONNECTION (self),
+ priv->session_monitor,
+ nm_auth_subject_get_uid (subject),
+ &error_desc)) {
+ error = g_error_new_literal (NM_SETTINGS_ERROR,
+ NM_SETTINGS_ERROR_PERMISSION_DENIED,
+ error_desc);
+ g_free (error_desc);
- if (!check_user_in_acl (NM_CONNECTION (self),
- context,
- priv->session_monitor,
- &sender_uid,
- &error)) {
callback (self, context, G_MAXULONG, error, callback_data);
g_clear_error (&error);
return;
}
- if (check_permission) {
- chain = nm_auth_chain_new (context, pk_auth_cb, self, &error_desc);
- if (chain) {
- priv->pending_auths = g_slist_append (priv->pending_auths, chain);
-
- nm_auth_chain_set_data (chain, "perm", (gpointer) check_permission, NULL);
- nm_auth_chain_set_data (chain, "callback", callback, NULL);
- nm_auth_chain_set_data (chain, "callback-data", callback_data, NULL);
- nm_auth_chain_set_data_ulong (chain, "sender-uid", sender_uid);
-
- nm_auth_chain_add_call (chain, check_permission, TRUE);
- } else {
- g_set_error_literal (&error,
- NM_SETTINGS_ERROR,
- NM_SETTINGS_ERROR_PERMISSION_DENIED,
- error_desc);
- callback (self, context, G_MAXULONG, error, callback_data);
- g_clear_error (&error);
- }
- } else {
+ if (!check_permission) {
/* Don't need polkit auth, automatic success */
- callback (self, context, sender_uid, NULL, callback_data);
+ callback (self, context, nm_auth_subject_get_uid (subject), NULL, callback_data);
+ return;
+ }
+
+ chain = nm_auth_chain_new_subject (subject, context, pk_auth_cb, self);
+ if (!chain) {
+ g_set_error_literal (&error,
+ NM_SETTINGS_ERROR,
+ NM_SETTINGS_ERROR_PERMISSION_DENIED,
+ "Unable to authenticate the request.");
+ callback (self, context, G_MAXULONG, error, callback_data);
+ g_clear_error (&error);
+ return;
}
+
+ priv->pending_auths = g_slist_append (priv->pending_auths, chain);
+ nm_auth_chain_set_data (chain, "perm", (gpointer) check_permission, NULL);
+ nm_auth_chain_set_data (chain, "callback", callback, NULL);
+ nm_auth_chain_set_data (chain, "callback-data", callback_data, NULL);
+ nm_auth_chain_set_data_ulong (chain, "sender-uid", sender_uid);
+ nm_auth_chain_add_call (chain, check_permission, TRUE);
}
/**** DBus method handlers ************************************/
@@ -1184,7 +1180,17 @@ static void
impl_settings_connection_get_settings (NMSettingsConnection *self,
DBusGMethodInvocation *context)
{
- auth_start (self, context, NULL, get_settings_auth_cb, NULL);
+ NMAuthSubject *subject;
+ GError *error = NULL;
+
+ subject = _new_auth_subject (context, &error);
+ if (subject) {
+ auth_start (self, context, subject, NULL, get_settings_auth_cb, NULL);
+ g_object_unref (subject);
+ } else {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ }
}
typedef struct {
@@ -1307,10 +1313,12 @@ impl_settings_connection_update_helper (NMSettingsConnection *self,
gboolean save_to_disk)
{
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
+ NMAuthSubject *subject = NULL;
NMConnection *tmp = NULL;
GError *error = NULL;
UpdateInfo *info;
const char *permission;
+ char *error_desc = NULL;
g_assert (new_settings != NULL || save_to_disk == TRUE);
@@ -1318,36 +1326,35 @@ impl_settings_connection_update_helper (NMSettingsConnection *self,
* the problem (ex a system settings plugin that can't write connections out)
* instead of over D-Bus.
*/
- if (!check_writable (NM_CONNECTION (self), &error)) {
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return;
- }
+ if (!check_writable (NM_CONNECTION (self), &error))
+ goto error;
/* Check if the settings are valid first */
if (new_settings) {
tmp = nm_connection_new_from_hash (new_settings, &error);
if (!tmp) {
g_assert (error);
- dbus_g_method_return_error (context, error);
- g_error_free (error);
- return;
+ goto error;
}
}
+ subject = _new_auth_subject (context, &error);
+ if (!subject)
+ goto error;
+
/* And that the new connection settings will be visible to the user
* that's sending the update request. You can't make a connection
* invisible to yourself.
*/
- if (!check_user_in_acl (tmp ? tmp : NM_CONNECTION (self),
- context,
- priv->session_monitor,
- NULL,
- &error)) {
- dbus_g_method_return_error (context, error);
- g_clear_error (&error);
- g_object_unref (tmp);
- return;
+ if (!nm_auth_uid_in_acl (tmp ? tmp : NM_CONNECTION (self),
+ priv->session_monitor,
+ nm_auth_subject_get_uid (subject),
+ &error_desc)) {
+ error = g_error_new_literal (NM_SETTINGS_ERROR,
+ NM_SETTINGS_ERROR_PERMISSION_DENIED,
+ error_desc);
+ g_free (error_desc);
+ goto error;
}
info = g_malloc0 (sizeof (*info));
@@ -1359,7 +1366,16 @@ impl_settings_connection_update_helper (NMSettingsConnection *self,
permission = get_update_modify_permission (NM_CONNECTION (self),
tmp ? tmp : NM_CONNECTION (self));
- auth_start (self, context, permission, update_auth_cb, info);
+ auth_start (self, context, subject, permission, update_auth_cb, info);
+ g_object_unref (subject);
+ return;
+
+error:
+ g_clear_object (&tmp);
+ g_clear_object (&subject);
+
+ dbus_g_method_return_error (context, error);
+ g_clear_error (&error);
}
static void
@@ -1440,6 +1456,7 @@ static void
impl_settings_connection_delete (NMSettingsConnection *self,
DBusGMethodInvocation *context)
{
+ NMAuthSubject *subject;
GError *error = NULL;
if (!check_writable (NM_CONNECTION (self), &error)) {
@@ -1448,7 +1465,14 @@ impl_settings_connection_delete (NMSettingsConnection *self,
return;
}
- auth_start (self, context, get_modify_permission_basic (self), delete_auth_cb, NULL);
+ subject = _new_auth_subject (context, &error);
+ if (subject) {
+ auth_start (self, context, subject, get_modify_permission_basic (self), delete_auth_cb, NULL);
+ g_object_unref (subject);
+ } else {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ }
}
/**************************************************************/
@@ -1524,11 +1548,22 @@ impl_settings_connection_get_secrets (NMSettingsConnection *self,
const gchar *setting_name,
DBusGMethodInvocation *context)
{
- auth_start (self,
- context,
- get_modify_permission_basic (self),
- dbus_secrets_auth_cb,
- g_strdup (setting_name));
+ NMAuthSubject *subject;
+ GError *error = NULL;
+
+ subject = _new_auth_subject (context, &error);
+ if (subject) {
+ auth_start (self,
+ context,
+ subject,
+ get_modify_permission_basic (self),
+ dbus_secrets_auth_cb,
+ g_strdup (setting_name));
+ g_object_unref (subject);
+ } else {
+ dbus_g_method_return_error (context, error);
+ g_error_free (error);
+ }
}
/**************************************************************/
diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c
index 2898888add..b5afbd71ab 100644
--- a/src/settings/nm-settings.c
+++ b/src/settings/nm-settings.c
@@ -1013,6 +1013,8 @@ pk_add_cb (NMAuthChain *chain,
const char *perm;
gboolean save_to_disk;
+ g_assert (context);
+
priv->auths = g_slist_remove (priv->auths, chain);
perm = nm_auth_chain_get_data (chain, "perm");
@@ -1092,13 +1094,15 @@ nm_settings_add_connection_dbus (NMSettings *self,
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
NMSettingConnection *s_con;
+ NMAuthSubject *subject = NULL;
NMAuthChain *chain;
GError *error = NULL, *tmp_error = NULL;
- gulong caller_uid = G_MAXULONG;
char *error_desc = NULL;
- const char *auth_error_desc = NULL;
const char *perm;
+ g_return_if_fail (connection != NULL);
+ g_return_if_fail (context != NULL);
+
/* Connection must be valid, of course */
if (!nm_connection_verify (connection, &tmp_error)) {
error = g_error_new (NM_SETTINGS_ERROR,
@@ -1106,9 +1110,7 @@ nm_settings_add_connection_dbus (NMSettings *self,
"The connection was invalid: %s",
tmp_error ? tmp_error->message : "(unknown)");
g_error_free (tmp_error);
- callback (self, NULL, error, context, user_data);
- g_error_free (error);
- return;
+ goto done;
}
/* The kernel doesn't support Ad-Hoc WPA connections well at this time,
@@ -1119,9 +1121,7 @@ nm_settings_add_connection_dbus (NMSettings *self,
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_CONNECTION,
"WPA Ad-Hoc disabled due to kernel bugs");
- callback (self, NULL, error, context, user_data);
- g_error_free (error);
- return;
+ goto done;
}
/* Do any of the plugins support adding? */
@@ -1129,32 +1129,29 @@ nm_settings_add_connection_dbus (NMSettings *self,
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_ADD_NOT_SUPPORTED,
"None of the registered plugins support add.");
- callback (self, NULL, error, context, user_data);
- g_error_free (error);
- return;
+ goto done;
}
- /* Get the caller's UID */
- if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, &caller_uid)) {
+ subject = nm_auth_subject_new_from_context (context);
+ if (!subject) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
- "Unable to determine request UID.");
- callback (self, NULL, error, context, user_data);
- g_error_free (error);
- return;
+ "Unable to determine UID of request.");
+ goto done;
}
/* Ensure the caller's username exists in the connection's permissions,
* or that the permissions is empty (ie, visible by everyone).
*/
- if (!nm_auth_uid_in_acl (connection, priv->session_monitor, caller_uid, &error_desc)) {
+ if (!nm_auth_uid_in_acl (connection,
+ priv->session_monitor,
+ nm_auth_subject_get_uid (subject),
+ &error_desc)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
error_desc);
g_free (error_desc);
- callback (self, NULL, error, context, user_data);
- g_error_free (error);
- return;
+ goto done;
}
/* If the caller is the only user in the connection's permissions, then
@@ -1169,23 +1166,29 @@ nm_settings_add_connection_dbus (NMSettings *self,
perm = NM_AUTH_PERMISSION_SETTINGS_MODIFY_SYSTEM;
/* Validate the user request */
- chain = nm_auth_chain_new (context, pk_add_cb, self, &auth_error_desc);
- if (chain) {
- priv->auths = g_slist_append (priv->auths, chain);
- nm_auth_chain_add_call (chain, perm, TRUE);
- nm_auth_chain_set_data (chain, "perm", (gpointer) perm, NULL);
- nm_auth_chain_set_data (chain, "connection", g_object_ref (connection), g_object_unref);
- nm_auth_chain_set_data (chain, "callback", callback, NULL);
- nm_auth_chain_set_data (chain, "callback-data", user_data, NULL);
- nm_auth_chain_set_data_ulong (chain, "caller-uid", caller_uid);
- nm_auth_chain_set_data (chain, "save-to-disk", GUINT_TO_POINTER (save_to_disk), NULL);
- } else {
+ chain = nm_auth_chain_new_subject (subject, context, pk_add_cb, self);
+ if (!chain) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
- auth_error_desc);
- callback (self, NULL, error, context, user_data);
- g_error_free (error);
+ "Unable to authenticate the request.");
+ goto done;
}
+
+ priv->auths = g_slist_append (priv->auths, chain);
+ nm_auth_chain_add_call (chain, perm, TRUE);
+ nm_auth_chain_set_data (chain, "perm", (gpointer) perm, NULL);
+ nm_auth_chain_set_data (chain, "connection", g_object_ref (connection), g_object_unref);
+ nm_auth_chain_set_data (chain, "callback", callback, NULL);
+ nm_auth_chain_set_data (chain, "callback-data", user_data, NULL);
+ nm_auth_chain_set_data_ulong (chain, "caller-uid", nm_auth_subject_get_uid (subject));
+ nm_auth_chain_set_data (chain, "save-to-disk", GUINT_TO_POINTER (save_to_disk), NULL);
+
+done:
+ if (error)
+ callback (self, NULL, error, context, user_data);
+
+ g_clear_error (&error);
+ g_clear_object (&subject);
}
static void
@@ -1251,7 +1254,7 @@ impl_settings_reload_connections (NMSettings *self,
gulong caller_uid;
GError *error = NULL;
- if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, &caller_uid)) {
+ if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, &caller_uid, NULL)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
"Unable to determine request UID.");
@@ -1294,6 +1297,8 @@ pk_hostname_cb (NMAuthChain *chain,
GSList *iter;
const char *hostname;
+ g_assert (context);
+
priv->auths = g_slist_remove (priv->auths, chain);
result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME);
@@ -1344,30 +1349,31 @@ impl_settings_save_hostname (NMSettings *self,
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
NMAuthChain *chain;
GError *error = NULL;
- const char *error_desc = NULL;
/* Do any of the plugins support setting the hostname? */
if (!get_plugin (self, NM_SYSTEM_CONFIG_INTERFACE_CAP_MODIFY_HOSTNAME)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_SAVE_HOSTNAME_NOT_SUPPORTED,
"None of the registered plugins support setting the hostname.");
- } else {
- chain = nm_auth_chain_new (context, pk_hostname_cb, self, &error_desc);
- if (chain) {
- priv->auths = g_slist_append (priv->auths, chain);
- nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, TRUE);
- nm_auth_chain_set_data (chain, "hostname", g_strdup (hostname), g_free);
- } else {
- error = g_error_new_literal (NM_SETTINGS_ERROR,
- NM_SETTINGS_ERROR_PERMISSION_DENIED,
- error_desc);
- }
+ goto done;
}
- if (error) {
- dbus_g_method_return_error (context, error);
- g_error_free (error);
+ chain = nm_auth_chain_new_context (context, pk_hostname_cb, self);
+ if (!chain) {
+ error = g_error_new_literal (NM_SETTINGS_ERROR,
+ NM_SETTINGS_ERROR_PERMISSION_DENIED,
+ "Unable to authenticate the request.");
+ goto done;
}
+
+ priv->auths = g_slist_append (priv->auths, chain);
+ nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_SETTINGS_MODIFY_HOSTNAME, TRUE);
+ nm_auth_chain_set_data (chain, "hostname", g_strdup (hostname), g_free);
+
+done:
+ if (error)
+ dbus_g_method_return_error (context, error);
+ g_clear_error (&error);
}
static gboolean
diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index 9f52a2a1fa..6962e301d0 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -71,9 +71,6 @@ typedef struct {
SecretsReq secrets_idx;
char *username;
- NMDevice *parent_dev;
- gulong device_monitor;
-
NMVPNConnectionState vpn_state;
NMVPNConnectionStateReason failure_reason;
DBusGProxy *proxy;
@@ -163,7 +160,7 @@ call_plugin_disconnect (NMVPNConnection *self)
}
static void
-vpn_cleanup (NMVPNConnection *connection)
+vpn_cleanup (NMVPNConnection *connection, NMDevice *parent_dev)
{
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
@@ -173,8 +170,8 @@ vpn_cleanup (NMVPNConnection *connection)
nm_platform_address_flush (priv->ip_ifindex);
}
- nm_device_set_vpn4_config (priv->parent_dev, NULL);
- nm_device_set_vpn6_config (priv->parent_dev, NULL);
+ nm_device_set_vpn4_config (parent_dev, NULL);
+ nm_device_set_vpn6_config (parent_dev, NULL);
g_free (priv->banner);
priv->banner = NULL;
@@ -197,6 +194,7 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
{
NMVPNConnectionPrivate *priv;
NMVPNConnectionState old_vpn_state;
+ NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (connection));
g_return_if_fail (NM_IS_VPN_CONNECTION (connection));
@@ -242,7 +240,7 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
/* Let dispatcher scripts know we're up and running */
nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_UP,
priv->connection,
- priv->parent_dev,
+ parent_dev,
priv->ip_iface,
priv->ip4_config,
priv->ip6_config,
@@ -255,7 +253,7 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
/* Let dispatcher scripts know we're about to go down */
nm_dispatcher_call_vpn (DISPATCHER_ACTION_VPN_DOWN,
priv->connection,
- priv->parent_dev,
+ parent_dev,
priv->ip_iface,
NULL,
NULL,
@@ -265,7 +263,7 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
/* Tear down and clean up the connection */
call_plugin_disconnect (connection);
- vpn_cleanup (connection);
+ vpn_cleanup (connection, parent_dev);
/* Fall through */
default:
priv->secrets_idx = SECRETS_REQ_SYSTEM;
@@ -276,26 +274,34 @@ nm_vpn_connection_set_vpn_state (NMVPNConnection *connection,
}
static void
-device_state_changed (NMDevice *device,
+device_state_changed (NMActiveConnection *active,
+ NMDevice *device,
NMDeviceState new_state,
- NMDeviceState old_state,
- NMDeviceStateReason reason,
- gpointer user_data)
+ NMDeviceState old_state)
{
- NMVPNConnection *connection = NM_VPN_CONNECTION (user_data);
-
if (new_state <= NM_DEVICE_STATE_DISCONNECTED) {
- nm_vpn_connection_set_vpn_state (connection,
+ nm_vpn_connection_set_vpn_state (NM_VPN_CONNECTION (active),
NM_VPN_CONNECTION_STATE_DISCONNECTED,
NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED);
} else if (new_state == NM_DEVICE_STATE_FAILED) {
- nm_vpn_connection_set_vpn_state (connection,
+ nm_vpn_connection_set_vpn_state (NM_VPN_CONNECTION (active),
NM_VPN_CONNECTION_STATE_FAILED,
NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED);
}
}
static void
+master_failed (NMActiveConnection *self)
+{
+ NMVPNConnection *connection = NM_VPN_CONNECTION (self);
+
+ /* Master failure fails the VPN */
+ nm_vpn_connection_set_vpn_state (connection,
+ NM_VPN_CONNECTION_STATE_FAILED,
+ NM_VPN_CONNECTION_STATE_REASON_DEVICE_DISCONNECTED);
+}
+
+static void
add_ip4_vpn_gateway_route (NMDevice *parent_device, guint32 vpn_gw)
{
NMIP4Config *parent_config;
@@ -400,26 +406,18 @@ NMVPNConnection *
nm_vpn_connection_new (NMConnection *connection,
NMDevice *parent_device,
const char *specific_object,
- gboolean user_requested,
- gulong user_uid)
+ NMAuthSubject *subject)
{
- NMVPNConnection *self;
-
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
g_return_val_if_fail (NM_IS_DEVICE (parent_device), NULL);
- self = (NMVPNConnection *) g_object_new (NM_TYPE_VPN_CONNECTION,
+ return (NMVPNConnection *) g_object_new (NM_TYPE_VPN_CONNECTION,
NM_ACTIVE_CONNECTION_INT_CONNECTION, connection,
NM_ACTIVE_CONNECTION_INT_DEVICE, parent_device,
NM_ACTIVE_CONNECTION_SPECIFIC_OBJECT, specific_object,
- NM_ACTIVE_CONNECTION_INT_USER_REQUESTED, user_requested,
- NM_ACTIVE_CONNECTION_INT_USER_UID, user_uid,
+ NM_ACTIVE_CONNECTION_INT_SUBJECT, subject,
NM_ACTIVE_CONNECTION_VPN, TRUE,
NULL);
- if (self)
- nm_active_connection_export (NM_ACTIVE_CONNECTION (self));
-
- return self;
}
static const char *
@@ -652,6 +650,7 @@ static gboolean
nm_vpn_connection_apply_config (NMVPNConnection *connection)
{
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (connection);
+ NMDevice *parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (connection));
nm_platform_link_set_up (priv->ip_ifindex);
@@ -668,9 +667,9 @@ nm_vpn_connection_apply_config (NMVPNConnection *connection)
/* Add any explicit route to the VPN gateway through the parent device */
if (priv->ip4_external_gw)
- add_ip4_vpn_gateway_route (priv->parent_dev, priv->ip4_external_gw);
+ add_ip4_vpn_gateway_route (parent_dev, priv->ip4_external_gw);
if (priv->ip6_external_gw)
- add_ip6_vpn_gateway_route (priv->parent_dev, priv->ip6_external_gw);
+ add_ip6_vpn_gateway_route (parent_dev, priv->ip6_external_gw);
nm_log_info (LOGD_VPN, "VPN connection '%s' (IP Config Get) complete.",
nm_connection_get_id (priv->connection));
@@ -1397,14 +1396,6 @@ nm_vpn_connection_get_ip_ifindex (NMVPNConnection *connection)
return NM_VPN_CONNECTION_GET_PRIVATE (connection)->ip_ifindex;
}
-NMDevice *
-nm_vpn_connection_get_parent_device (NMVPNConnection *connection)
-{
- g_return_val_if_fail (NM_IS_VPN_CONNECTION (connection), NULL);
-
- return NM_VPN_CONNECTION_GET_PRIVATE (connection)->parent_dev;
-}
-
guint32
nm_vpn_connection_get_ip4_internal_gateway (NMVPNConnection *connection)
{
@@ -1674,23 +1665,12 @@ nm_vpn_connection_init (NMVPNConnection *self)
static void
constructed (GObject *object)
{
- NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (object);
NMConnection *connection;
- NMDevice *device;
G_OBJECT_CLASS (nm_vpn_connection_parent_class)->constructed (object);
connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (object));
- priv->connection = g_object_ref (connection);
-
- device = (NMDevice *) nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object));
- g_assert (device);
-
- priv->parent_dev = g_object_ref (device);
-
- priv->device_monitor = g_signal_connect (device, "state-changed",
- G_CALLBACK (device_state_changed),
- object);
+ NM_VPN_CONNECTION_GET_PRIVATE (object)->connection = g_object_ref (connection);
}
static void
@@ -1712,11 +1692,6 @@ dispose (GObject *object)
if (priv->ip6_external_gw)
g_free (priv->ip6_external_gw);
- if (priv->device_monitor)
- g_signal_handler_disconnect (priv->parent_dev, priv->device_monitor);
-
- g_clear_object (&priv->parent_dev);
-
if (priv->ip4_config)
g_object_unref (priv->ip4_config);
if (priv->ip6_config)
@@ -1755,6 +1730,7 @@ get_property (GObject *object, guint prop_id,
GValue *value, GParamSpec *pspec)
{
NMVPNConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (object);
+ NMDevice *parent_dev;
switch (prop_id) {
case PROP_VPN_STATE:
@@ -1764,7 +1740,8 @@ get_property (GObject *object, guint prop_id,
g_value_set_string (value, priv->banner ? priv->banner : "");
break;
case PROP_MASTER:
- g_value_set_boxed (value, nm_device_get_path (priv->parent_dev));
+ parent_dev = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (object));
+ g_value_set_boxed (value, parent_dev ? nm_device_get_path (parent_dev) : "/");
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
@@ -1776,6 +1753,7 @@ static void
nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class)
{
GObjectClass *object_class = G_OBJECT_CLASS (connection_class);
+ NMActiveConnectionClass *active_class = NM_ACTIVE_CONNECTION_CLASS (connection_class);
g_type_class_add_private (connection_class, sizeof (NMVPNConnectionPrivate));
@@ -1784,6 +1762,8 @@ nm_vpn_connection_class_init (NMVPNConnectionClass *connection_class)
object_class->constructed = constructed;
object_class->dispose = dispose;
object_class->finalize = finalize;
+ active_class->master_failed = master_failed;
+ active_class->device_state_changed = device_state_changed;
g_object_class_override_property (object_class, PROP_MASTER, NM_ACTIVE_CONNECTION_MASTER);
diff --git a/src/vpn-manager/nm-vpn-connection.h b/src/vpn-manager/nm-vpn-connection.h
index bf5433456d..b98dcbe629 100644
--- a/src/vpn-manager/nm-vpn-connection.h
+++ b/src/vpn-manager/nm-vpn-connection.h
@@ -26,6 +26,7 @@
#include <glib-object.h>
#include "NetworkManagerVPN.h"
#include "nm-device.h"
+#include "nm-auth-subject.h"
#define NM_TYPE_VPN_CONNECTION (nm_vpn_connection_get_type ())
#define NM_VPN_CONNECTION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_VPN_CONNECTION, NMVPNConnection))
@@ -67,8 +68,7 @@ GType nm_vpn_connection_get_type (void);
NMVPNConnection * nm_vpn_connection_new (NMConnection *connection,
NMDevice *parent_device,
const char *specific_object,
- gboolean user_requested,
- gulong user_uid);
+ NMAuthSubject *subject);
void nm_vpn_connection_activate (NMVPNConnection *connection);
NMConnection * nm_vpn_connection_get_connection (NMVPNConnection *connection);
@@ -82,7 +82,6 @@ NMIP4Config * nm_vpn_connection_get_ip4_config (NMVPNConnection *connect
NMIP6Config * nm_vpn_connection_get_ip6_config (NMVPNConnection *connection);
const char * nm_vpn_connection_get_ip_iface (NMVPNConnection *connection);
int nm_vpn_connection_get_ip_ifindex (NMVPNConnection *connection);
-NMDevice * nm_vpn_connection_get_parent_device (NMVPNConnection *connection);
guint32 nm_vpn_connection_get_ip4_internal_gateway (NMVPNConnection *connection);
struct in6_addr * nm_vpn_connection_get_ip6_internal_gateway (NMVPNConnection *connection);
diff --git a/src/vpn-manager/nm-vpn-manager.c b/src/vpn-manager/nm-vpn-manager.c
index 9cd140e54e..6c63edc1e7 100644
--- a/src/vpn-manager/nm-vpn-manager.c
+++ b/src/vpn-manager/nm-vpn-manager.c
@@ -78,7 +78,7 @@ get_service_by_namefile (NMVPNManager *self, const char *namefile)
}
static NMVPNConnection *
-find_active_vpn_connection_by_connection (NMVPNManager *self, NMConnection *connection)
+find_active_vpn_connection (NMVPNManager *self, NMConnection *connection)
{
NMVPNManagerPrivate *priv = NM_VPN_MANAGER_GET_PRIVATE (self);
GHashTableIter iter;
@@ -104,66 +104,53 @@ find_active_vpn_connection_by_connection (NMVPNManager *self, NMConnection *conn
return found;
}
-NMActiveConnection *
+gboolean
nm_vpn_manager_activate_connection (NMVPNManager *manager,
- NMConnection *connection,
- NMDevice *device,
- const char *specific_object,
- gboolean user_requested,
- gulong user_uid,
+ NMVPNConnection *vpn,
GError **error)
{
- NMSettingVPN *vpn_setting;
+ NMVPNConnection *existing = NULL;
+ NMConnection *connection;
+ NMSettingVPN *s_vpn;
NMVPNService *service;
- NMVPNConnection *vpn = NULL;
const char *service_name;
+ NMDevice *device;
- g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), NULL);
- g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
- g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
- g_return_val_if_fail (error != NULL, NULL);
- g_return_val_if_fail (*error == NULL, NULL);
+ g_return_val_if_fail (NM_IS_VPN_MANAGER (manager), FALSE);
+ g_return_val_if_fail (NM_IS_VPN_CONNECTION (vpn), FALSE);
+ g_return_val_if_fail (error != NULL, FALSE);
+ g_return_val_if_fail (*error == NULL, FALSE);
+ device = nm_active_connection_get_device (NM_ACTIVE_CONNECTION (vpn));
+ g_assert (device);
if ( nm_device_get_state (device) != NM_DEVICE_STATE_ACTIVATED
&& nm_device_get_state (device) != NM_DEVICE_STATE_SECONDARIES) {
- g_set_error (error,
- NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_DEVICE_NOT_ACTIVE,
- "%s", "The base device for the VPN connection was not active.");
- return NULL;
+ g_set_error_literal (error, NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_DEVICE_NOT_ACTIVE,
+ "The base device for the VPN connection was not active.");
+ return FALSE;
}
- vpn_setting = nm_connection_get_setting_vpn (connection);
- if (!vpn_setting) {
- g_set_error (error,
- NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_CONNECTION_INVALID,
- "%s", "The connection was not a VPN connection.");
- return NULL;
- }
+ connection = nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (vpn));
+ g_assert (connection);
+ s_vpn = nm_connection_get_setting_vpn (connection);
+ g_assert (s_vpn);
- vpn = find_active_vpn_connection_by_connection (manager, connection);
- if (vpn) {
- nm_vpn_connection_disconnect (vpn, NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED);
- vpn = NULL;
- }
-
- service_name = nm_setting_vpn_get_service_type (vpn_setting);
+ service_name = nm_setting_vpn_get_service_type (s_vpn);
g_assert (service_name);
service = g_hash_table_lookup (NM_VPN_MANAGER_GET_PRIVATE (manager)->services, service_name);
if (!service) {
- g_set_error (error,
- NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_SERVICE_INVALID,
+ g_set_error (error, NM_VPN_MANAGER_ERROR, NM_VPN_MANAGER_ERROR_SERVICE_INVALID,
"The VPN service '%s' was not installed.",
service_name);
- return NULL;
+ return FALSE;
}
- return (NMActiveConnection *) nm_vpn_service_activate (service,
- connection,
- device,
- specific_object,
- user_requested,
- user_uid,
- error);
+ existing = find_active_vpn_connection (manager,
+ nm_active_connection_get_connection (NM_ACTIVE_CONNECTION (vpn)));
+ if (existing)
+ nm_vpn_connection_disconnect (vpn, NM_VPN_CONNECTION_STATE_REASON_USER_DISCONNECTED);
+
+ return nm_vpn_service_activate (service, vpn, error);
}
gboolean
diff --git a/src/vpn-manager/nm-vpn-manager.h b/src/vpn-manager/nm-vpn-manager.h
index 1d398ea2cb..57f947b0e4 100644
--- a/src/vpn-manager/nm-vpn-manager.h
+++ b/src/vpn-manager/nm-vpn-manager.h
@@ -59,13 +59,9 @@ GType nm_vpn_manager_get_type (void);
NMVPNManager *nm_vpn_manager_get (void);
-NMActiveConnection *nm_vpn_manager_activate_connection (NMVPNManager *manager,
- NMConnection *connection,
- NMDevice *device,
- const char *specific_object,
- gboolean user_requested,
- gulong user_uid,
- GError **error);
+gboolean nm_vpn_manager_activate_connection (NMVPNManager *manager,
+ NMVPNConnection *vpn,
+ GError **error);
gboolean nm_vpn_manager_deactivate_connection (NMVPNManager *manager,
NMVPNConnection *connection,
diff --git a/src/vpn-manager/nm-vpn-service.c b/src/vpn-manager/nm-vpn-service.c
index a34c782e73..8ecd9a1176 100644
--- a/src/vpn-manager/nm-vpn-service.c
+++ b/src/vpn-manager/nm-vpn-service.c
@@ -323,45 +323,37 @@ connection_vpn_state_changed (NMVPNConnection *connection,
}
}
-NMVPNConnection *
+gboolean
nm_vpn_service_activate (NMVPNService *service,
- NMConnection *connection,
- NMDevice *device,
- const char *specific_object,
- gboolean user_requested,
- gulong user_uid,
+ NMVPNConnection *vpn,
GError **error)
{
- NMVPNConnection *vpn;
NMVPNServicePrivate *priv;
- g_return_val_if_fail (NM_IS_VPN_SERVICE (service), NULL);
- g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
- g_return_val_if_fail (NM_IS_DEVICE (device), NULL);
- g_return_val_if_fail (error != NULL, NULL);
- g_return_val_if_fail (*error == NULL, NULL);
+ g_return_val_if_fail (NM_IS_VPN_SERVICE (service), FALSE);
+ g_return_val_if_fail (NM_IS_VPN_CONNECTION (vpn), FALSE);
+ g_return_val_if_fail (error != NULL, FALSE);
+ g_return_val_if_fail (*error == NULL, FALSE);
priv = NM_VPN_SERVICE_GET_PRIVATE (service);
clear_quit_timeout (service);
- vpn = nm_vpn_connection_new (connection, device, specific_object, user_requested, user_uid);
g_signal_connect (vpn, NM_VPN_CONNECTION_INTERNAL_STATE_CHANGED,
G_CALLBACK (connection_vpn_state_changed),
service);
priv->connections = g_slist_prepend (priv->connections, g_object_ref (vpn));
- if (nm_dbus_manager_name_has_owner (priv->dbus_mgr, priv->dbus_service)) {
- // FIXME: fill in error when errors happen
+ if (nm_dbus_manager_name_has_owner (priv->dbus_mgr, priv->dbus_service))
nm_vpn_connection_activate (vpn);
- } else if (priv->start_timeout == 0) {
+ else if (priv->start_timeout == 0) {
nm_log_info (LOGD_VPN, "Starting VPN service '%s'...", priv->name);
if (!nm_vpn_service_daemon_exec (service, error))
- vpn = NULL;
+ return FALSE;
}
- return vpn;
+ return TRUE;
}
const GSList *
diff --git a/src/vpn-manager/nm-vpn-service.h b/src/vpn-manager/nm-vpn-service.h
index e883d55f8b..2ad79a0d6b 100644
--- a/src/vpn-manager/nm-vpn-service.h
+++ b/src/vpn-manager/nm-vpn-service.h
@@ -54,13 +54,9 @@ const char *nm_vpn_service_get_dbus_service (NMVPNService *service);
/* Returns the path of the VPN service's .name file */
const char *nm_vpn_service_get_name_file (NMVPNService *service);
-NMVPNConnection * nm_vpn_service_activate (NMVPNService *service,
- NMConnection *connection,
- NMDevice *device,
- const char *specific_object,
- gboolean user_requested,
- gulong user_uid,
- GError **error);
+gboolean nm_vpn_service_activate (NMVPNService *service,
+ NMVPNConnection *vpn,
+ GError **error);
const GSList *nm_vpn_service_get_active_connections (NMVPNService *service);