summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-11-21 13:30:16 +0100
committerThomas Haller <thaller@redhat.com>2018-12-04 13:15:18 +0100
commit1207cced351147675da3d63488bc8888a3994202 (patch)
tree953078d7141278581da634f25a37639f00750788
parent9c636331d2ed1e225aa3cfbefe664625420fe754 (diff)
downloadNetworkManager-th/keep-alive-fixes.tar.gz
core: improve and fix keeping connection active based on "connection.permissions"th/keep-alive-fixes
By setting "connection.permissions", a profile is restricted to a particular user. That means for example, that another user cannot see, modify, delete, activate or deactivate the profile. It also means, that the profile will only autoconnect when the user is logged in (has a session). Note that root is always able to activate the profile. Likewise, the user is also allowed to manually activate the own profile, even if no session currently exists (which can easily happen with `sudo`). When the user logs out (the session goes away), we want do disconnect the profile, however there are conflicting goals here: 1) if the profile was activate by root user, then logging out the user should not disconnect the profile. The patch fixes that by not binding the activation to the connection, if the activation is done by the root user. 2) if the profile was activated by the owner when it had no session, then it should stay alive until the user logs in (once) and logs out again. This is already handled by the previous commit. Yes, this point is odd. If you first do $ sudo -u $OTHER_USER nmcli connection up $PROFILE the profile activates despite not having a session. If you then $ ssh guest@localhost nmcli device you'll still see the profile active. However, the moment the SSH session ends, a session closes and the profile disconnects. It's unclear, how to solve that any better. I think, a user who cares about this, should not activate the profile without having a session in the first place. There are quite some special cases, in particular with internal activations. In those cases we need to decide whether to bind the activation to the profile's visibility. Also, expose the "bind" setting in the D-Bus API. Note, that in the future this flag may be modified via D-Bus API. Like we may also add related API that allows to tweak the lifetime of the activation. Also, I think we broke handling of connection visiblity with 37e8c53eeed "core: Introduce helper class to track connection keep alive". This should be fixed now too, with improved behavior. Fixes: 37e8c53eeed579fe34a68819cd12f3295d581394 https://bugzilla.redhat.com/show_bug.cgi?id=1530977
-rw-r--r--libnm-core/nm-dbus-interface.h19
-rw-r--r--src/devices/nm-device.c19
-rw-r--r--src/devices/nm-device.h1
-rw-r--r--src/nm-act-request.c3
-rw-r--r--src/nm-act-request.h1
-rw-r--r--src/nm-active-connection.c45
-rw-r--r--src/nm-active-connection.h7
-rw-r--r--src/nm-checkpoint.c6
-rw-r--r--src/nm-manager.c93
-rw-r--r--src/nm-manager.h1
-rw-r--r--src/nm-policy.c12
-rw-r--r--src/vpn/nm-vpn-connection.c2
-rw-r--r--src/vpn/nm-vpn-connection.h1
13 files changed, 181 insertions, 29 deletions
diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h
index 28683c1dd4..aac4d7eadd 100644
--- a/libnm-core/nm-dbus-interface.h
+++ b/libnm-core/nm-dbus-interface.h
@@ -960,20 +960,25 @@ typedef enum { /*< flags >*/
* @NM_ACTIVATION_STATE_FLAG_IP6_READY: IPv6 setting is completed.
* @NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES: The master has any slave devices attached.
* This only makes sense if the device is a master.
+ * @NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY: the lifetime
+ * of the activation is bound to the visilibity of the connection profile,
+ * which in turn depends on "connection.permissions" and whether a session
+ * for the user exists. Since: 1.16
*
* Flags describing the current activation state.
*
* Since: 1.10
**/
typedef enum { /*< flags >*/
- NM_ACTIVATION_STATE_FLAG_NONE = 0,
+ NM_ACTIVATION_STATE_FLAG_NONE = 0,
- NM_ACTIVATION_STATE_FLAG_IS_MASTER = (1LL << 0),
- NM_ACTIVATION_STATE_FLAG_IS_SLAVE = (1LL << 1),
- NM_ACTIVATION_STATE_FLAG_LAYER2_READY = (1LL << 2),
- NM_ACTIVATION_STATE_FLAG_IP4_READY = (1LL << 3),
- NM_ACTIVATION_STATE_FLAG_IP6_READY = (1LL << 4),
- NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES = (1LL << 5),
+ NM_ACTIVATION_STATE_FLAG_IS_MASTER = (1LL << 0),
+ NM_ACTIVATION_STATE_FLAG_IS_SLAVE = (1LL << 1),
+ NM_ACTIVATION_STATE_FLAG_LAYER2_READY = (1LL << 2),
+ NM_ACTIVATION_STATE_FLAG_IP4_READY = (1LL << 3),
+ NM_ACTIVATION_STATE_FLAG_IP6_READY = (1LL << 4),
+ NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES = (1LL << 5),
+ NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY = (1LL << 6),
} NMActivationStateFlags;
/**
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 55c5cfdccd..1cee1f179f 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -2384,10 +2384,27 @@ nm_device_get_act_request (NMDevice *self)
return NM_DEVICE_GET_PRIVATE (self)->act_request.obj;
}
+NMActivationStateFlags
+nm_device_get_activation_state_flags (NMDevice *self)
+{
+ NMActRequest *ac;
+
+ g_return_val_if_fail (NM_IS_DEVICE (self), NM_ACTIVATION_STATE_FLAG_NONE);
+
+ ac = NM_DEVICE_GET_PRIVATE (self)->act_request.obj;
+ if (!ac)
+ return NM_ACTIVATION_STATE_FLAG_NONE;
+ return nm_active_connection_get_state_flags (NM_ACTIVE_CONNECTION (ac));
+}
+
NMSettingsConnection *
nm_device_get_settings_connection (NMDevice *self)
{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ NMDevicePrivate *priv;
+
+ g_return_val_if_fail (NM_IS_DEVICE (self), NULL);
+
+ priv = NM_DEVICE_GET_PRIVATE (self);
return priv->act_request.obj ? nm_act_request_get_settings_connection (priv->act_request.obj) : NULL;
}
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index 4851f36fee..cd07e24630 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -543,6 +543,7 @@ NMConnection * nm_device_get_settings_connection_get_connection (NMDevice *self
NMConnection * nm_device_get_applied_connection (NMDevice *dev);
gboolean nm_device_has_unmodified_applied_connection (NMDevice *self,
NMSettingCompareFlags compare_flags);
+NMActivationStateFlags nm_device_get_activation_state_flags (NMDevice *self);
gpointer /* (NMSetting *) */ nm_device_get_applied_setting (NMDevice *dev,
GType setting_type);
diff --git a/src/nm-act-request.c b/src/nm-act-request.c
index e4c65e59ea..cd81696490 100644
--- a/src/nm-act-request.c
+++ b/src/nm-act-request.c
@@ -539,6 +539,7 @@ nm_act_request_init (NMActRequest *req)
* @subject: the #NMAuthSubject representing the requestor of the activation
* @activation_type: the #NMActivationType
* @activation_reason: the reason for activation
+ * @initial_state_flags: the initial state flags.
* @device: the device/interface to configure according to @connection
*
* Creates a new device-based activation request. If an applied connection is
@@ -553,6 +554,7 @@ nm_act_request_new (NMSettingsConnection *settings_connection,
NMAuthSubject *subject,
NMActivationType activation_type,
NMActivationReason activation_reason,
+ NMActivationStateFlags initial_state_flags,
NMDevice *device)
{
g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL);
@@ -567,6 +569,7 @@ nm_act_request_new (NMSettingsConnection *settings_connection,
NM_ACTIVE_CONNECTION_INT_SUBJECT, subject,
NM_ACTIVE_CONNECTION_INT_ACTIVATION_TYPE, (int) activation_type,
NM_ACTIVE_CONNECTION_INT_ACTIVATION_REASON, (int) activation_reason,
+ NM_ACTIVE_CONNECTION_STATE_FLAGS, (guint) initial_state_flags,
NULL);
}
diff --git a/src/nm-act-request.h b/src/nm-act-request.h
index a8f09271a1..af2b749055 100644
--- a/src/nm-act-request.h
+++ b/src/nm-act-request.h
@@ -42,6 +42,7 @@ NMActRequest *nm_act_request_new (NMSettingsConnection *settings_connec
NMAuthSubject *subject,
NMActivationType activation_type,
NMActivationReason activation_reason,
+ NMActivationStateFlags initial_state_flags,
NMDevice *device);
NMSettingsConnection *nm_act_request_get_settings_connection (NMActRequest *req);
diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c
index 96f164638d..966a274351 100644
--- a/src/nm-active-connection.c
+++ b/src/nm-active-connection.c
@@ -163,14 +163,18 @@ NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_state_to_string, NMActiveConnectionState,
);
#define state_to_string(state) NM_UTILS_LOOKUP_STR (_state_to_string, state)
+/* the maximum required buffer size for _state_flags_to_string(). */
+#define _NM_ACTIVATION_STATE_FLAG_TO_STRING_BUFSIZE (255)
+
NM_UTILS_FLAGS2STR_DEFINE_STATIC (_state_flags_to_string, NMActivationStateFlags,
- NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_NONE, "none"),
- NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IS_MASTER, "is-master"),
- NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IS_SLAVE, "is-slave"),
- NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_LAYER2_READY, "layer2-ready"),
- NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IP4_READY, "ip4-ready"),
- NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IP6_READY, "ip6-ready"),
- NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES, "master-has-slaves"),
+ NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_NONE, "none"),
+ NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IS_MASTER, "is-master"),
+ NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IS_SLAVE, "is-slave"),
+ NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_LAYER2_READY, "layer2-ready"),
+ NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IP4_READY, "ip4-ready"),
+ NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_IP6_READY, "ip6-ready"),
+ NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_MASTER_HAS_SLAVES, "master-has-slaves"),
+ NM_UTILS_FLAGS2STR (NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY, "lifetime-bound-to-profile-visibility"),
);
/*****************************************************************************/
@@ -361,14 +365,20 @@ nm_active_connection_set_state_flags_full (NMActiveConnection *self,
f = (priv->state_flags & ~mask) | (state_flags & mask);
if (f != priv->state_flags) {
- char buf1[G_N_ELEMENTS (_nm_utils_to_string_buffer)];
- char buf2[G_N_ELEMENTS (_nm_utils_to_string_buffer)];
+ char buf1[_NM_ACTIVATION_STATE_FLAG_TO_STRING_BUFSIZE];
+ char buf2[_NM_ACTIVATION_STATE_FLAG_TO_STRING_BUFSIZE];
_LOGD ("set state-flags %s (was %s)",
_state_flags_to_string (f, buf1, sizeof (buf1)),
_state_flags_to_string (priv->state_flags, buf2, sizeof (buf2)));
priv->state_flags = f;
_notify (self, PROP_STATE_FLAGS);
+
+ nm_keep_alive_set_settings_connection_watch_visible (priv->keep_alive,
+ NM_FLAGS_HAS (priv->state_flags,
+ NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY)
+ ? priv->settings_connection.obj
+ : NULL);
}
}
@@ -1384,6 +1394,12 @@ set_property (GObject *object, guint prop_id,
g_return_if_reached ();
_set_activation_type (self, (NMActivationType) i);
break;
+ case PROP_STATE_FLAGS:
+ /* construct-only */
+ priv->state_flags = g_value_get_uint (value);
+ nm_assert ((guint) priv->state_flags == g_value_get_uint (value));
+ nm_assert (!NM_FLAGS_ANY (priv->state_flags, ~NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY));
+ break;
case PROP_INT_ACTIVATION_REASON:
/* construct-only */
i = g_value_get_int (value);
@@ -1467,13 +1483,12 @@ constructed (GObject *object)
g_steal_pointer (&priv->applied_connection));
}
+ if (NM_FLAGS_HAS (priv->state_flags,
+ NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY))
+ nm_keep_alive_set_settings_connection_watch_visible (priv->keep_alive, priv->settings_connection.obj);
+
g_return_if_fail (priv->subject);
g_return_if_fail (priv->activation_reason != NM_ACTIVATION_REASON_UNSET);
-
- if (NM_IN_SET ((NMActivationReason) priv->activation_reason,
- NM_ACTIVATION_REASON_AUTOCONNECT,
- NM_ACTIVATION_REASON_AUTOCONNECT_SLAVES))
- nm_keep_alive_set_settings_connection_watch_visible (priv->keep_alive, priv->settings_connection.obj);
}
static void
@@ -1625,7 +1640,7 @@ nm_active_connection_class_init (NMActiveConnectionClass *ac_class)
obj_properties[PROP_STATE_FLAGS] =
g_param_spec_uint (NM_ACTIVE_CONNECTION_STATE_FLAGS, "", "",
0, G_MAXUINT32, NM_ACTIVATION_STATE_FLAG_NONE,
- G_PARAM_READABLE |
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY |
G_PARAM_STATIC_STRINGS);
obj_properties[PROP_DEFAULT] =
diff --git a/src/nm-active-connection.h b/src/nm-active-connection.h
index 2b5a6b59ee..1d4ce29e4e 100644
--- a/src/nm-active-connection.h
+++ b/src/nm-active-connection.h
@@ -163,6 +163,13 @@ nm_active_connection_set_state_flags (NMActiveConnection *self,
nm_active_connection_set_state_flags_full (self, state_flags, state_flags);
}
+static inline void
+nm_active_connection_set_state_flags_clear (NMActiveConnection *self,
+ NMActivationStateFlags state_flags)
+{
+ nm_active_connection_set_state_flags_full (self, NM_ACTIVATION_STATE_FLAG_NONE, state_flags);
+}
+
NMDevice * nm_active_connection_get_device (NMActiveConnection *self);
gboolean nm_active_connection_set_device (NMActiveConnection *self, NMDevice *device);
diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c
index b0cf1f5117..5489ed4956 100644
--- a/src/nm-checkpoint.c
+++ b/src/nm-checkpoint.c
@@ -46,6 +46,7 @@ typedef struct {
guint64 ac_version_id;
NMDeviceState state;
bool realized:1;
+ bool activation_lifetime_bound_to_profile_visiblity:1;
NMUnmanFlagOp unmanaged_explicit;
NMActivationReason activation_reason;
} DeviceCheckpoint;
@@ -335,6 +336,9 @@ activate:
subject,
NM_ACTIVATION_TYPE_MANAGED,
dev_checkpoint->activation_reason,
+ dev_checkpoint->activation_lifetime_bound_to_profile_visiblity
+ ? NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY
+ : NM_ACTIVATION_STATE_FLAG_NONE,
&local_error)) {
_LOGW ("rollback: reactivation of connection %s/%s failed: %s",
nm_settings_connection_get_id (connection),
@@ -439,6 +443,8 @@ device_checkpoint_create (NMDevice *device)
dev_checkpoint->settings_connection = nm_simple_connection_new_clone (nm_settings_connection_get_connection (settings_connection));
dev_checkpoint->ac_version_id = nm_active_connection_version_id_get (NM_ACTIVE_CONNECTION (act_request));
dev_checkpoint->activation_reason = nm_active_connection_get_activation_reason (NM_ACTIVE_CONNECTION (act_request));
+ dev_checkpoint->activation_lifetime_bound_to_profile_visiblity = NM_FLAGS_HAS (nm_active_connection_get_state_flags (NM_ACTIVE_CONNECTION (act_request)),
+ NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY);
}
return dev_checkpoint;
diff --git a/src/nm-manager.c b/src/nm-manager.c
index cae38b1c80..41e5e69ea2 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -320,6 +320,7 @@ static NMActiveConnection *_new_active_connection (NMManager *self,
NMAuthSubject *subject,
NMActivationType activation_type,
NMActivationReason activation_reason,
+ NMActivationStateFlags initial_state_flags,
GError **error);
static void policy_activating_ac_changed (GObject *object, GParamSpec *pspec, gpointer user_data);
@@ -2693,6 +2694,18 @@ recheck_assume_connection (NMManager *self,
GError *error = NULL;
subject = nm_auth_subject_new_internal ();
+
+ /* Note: the lifetime of the activation connection is always bound to the profiles visiblity
+ * via NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY.
+ *
+ * This only makes a difference, if the profile actually has "connection.permissions"
+ * set to limit visibility (which is not the case for externally managed, generated profiles).
+ *
+ * If we assume a previously active connection whose lifetime was unbound, we now bind it
+ * after restart. That is not correct, and can mean that the profile becomes subject to
+ * deactivation after restart (if the user logs out).
+ *
+ * This should be improved, but it's unclear how. */
active = _new_active_connection (self,
FALSE,
sett_conn,
@@ -2703,6 +2716,7 @@ recheck_assume_connection (NMManager *self,
subject,
generated ? NM_ACTIVATION_TYPE_EXTERNAL : NM_ACTIVATION_TYPE_ASSUME,
generated ? NM_ACTIVATION_REASON_EXTERNAL : NM_ACTIVATION_REASON_ASSUME,
+ NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY,
&error);
if (!active) {
@@ -3887,11 +3901,16 @@ ensure_master_active_connection (NMManager *self,
GError **error)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
+ NMActiveConnection *ac;
NMActiveConnection *master_ac = NULL;
NMDeviceState master_state;
+ gboolean bind_lifetime_to_profile_visibility;
+
+ g_return_val_if_fail (connection, NULL);
+ g_return_val_if_fail (master_connection || master_device, FALSE);
- g_assert (connection);
- g_assert (master_connection || master_device);
+ bind_lifetime_to_profile_visibility = NM_FLAGS_HAS (nm_device_get_activation_state_flags (device),
+ NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY);
/* If the master device isn't activated then we need to activate it using
* compatible connection. If it's already activating we can just proceed.
@@ -3916,8 +3935,16 @@ ensure_master_active_connection (NMManager *self,
if ( (master_state == NM_DEVICE_STATE_ACTIVATED)
|| nm_device_is_activating (master_device)) {
/* Device already using master_connection */
- g_assert (device_connection);
- return NM_ACTIVE_CONNECTION (nm_device_get_act_request (master_device));
+ ac = NM_ACTIVE_CONNECTION (nm_device_get_act_request (master_device));
+ g_return_val_if_fail (device_connection, ac);
+
+ if (!bind_lifetime_to_profile_visibility) {
+ /* unbind the lifetime. */
+ nm_active_connection_set_state_flags_clear (ac,
+ NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY);
+ }
+
+ return ac;
}
/* If the device is disconnected, find a compatible connection and
@@ -3954,6 +3981,9 @@ ensure_master_active_connection (NMManager *self,
subject,
NM_ACTIVATION_TYPE_MANAGED,
activation_reason,
+ bind_lifetime_to_profile_visibility
+ ? NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY
+ : NM_ACTIVATION_STATE_FLAG_NONE,
error);
return master_ac;
}
@@ -4002,6 +4032,9 @@ ensure_master_active_connection (NMManager *self,
subject,
NM_ACTIVATION_TYPE_MANAGED,
activation_reason,
+ bind_lifetime_to_profile_visibility
+ ? NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY
+ : NM_ACTIVATION_STATE_FLAG_NONE,
error);
return master_ac;
}
@@ -4163,6 +4196,7 @@ autoconnect_slaves (NMManager *self,
master_device)) {
gs_free SlaveConnectionInfo *slaves = NULL;
guint i, n_slaves = 0;
+ gboolean bind_lifetime_to_profile_visibility;
slaves = find_slaves (self, master_connection, master_device, &n_slaves);
if (n_slaves > 1) {
@@ -4177,6 +4211,10 @@ autoconnect_slaves (NMManager *self,
GINT_TO_POINTER (!nm_streq0 (value, "index")));
}
+ bind_lifetime_to_profile_visibility = n_slaves > 0
+ && NM_FLAGS_HAS (nm_device_get_activation_state_flags (master_device),
+ NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY);
+
for (i = 0; i < n_slaves; i++) {
SlaveConnectionInfo *slave = &slaves[i];
const char *uuid;
@@ -4231,6 +4269,9 @@ autoconnect_slaves (NMManager *self,
subject,
NM_ACTIVATION_TYPE_MANAGED,
NM_ACTIVATION_REASON_AUTOCONNECT_SLAVES,
+ bind_lifetime_to_profile_visibility
+ ? NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY
+ : NM_ACTIVATION_STATE_FLAG_NONE,
&local_err);
if (local_err) {
_LOGW (LOGD_CORE, "Slave connection activation failed: %s", local_err->message);
@@ -4291,6 +4332,40 @@ unmanaged_to_disconnected (NMDevice *device)
}
}
+static NMActivationStateFlags
+_activation_bind_lifetime_to_profile_visibility (NMAuthSubject *subject)
+{
+ if ( nm_auth_subject_is_internal (subject)
+ || nm_auth_subject_get_unix_process_uid (subject) == 0) {
+ /* internal requests and requests from root are always unbound. */
+ return NM_ACTIVATION_STATE_FLAG_NONE;
+ }
+
+ /* if the activation was not done by internal decision nor root, there
+ * are the following cases:
+ *
+ * - the connection has "connection.permissions" unset and the profile
+ * is not restricted to a user and commonly always visible. It does
+ * not hurt to bind the lifetime, because we expect the profile to be
+ * visible at the moment. If the profile changes (while still being active),
+ * we want to pick-up changes to the visibility and possibly disconnect.
+ *
+ * - the connection has "connection.permissions" set, and the current user
+ * is the owner:
+ *
+ * - Usually, we would expect that the profile is visible at the moment,
+ * and of course we want to bind the lifetime. The moment the user
+ * logs out, the connection becomes invisible and disconnects.
+ *
+ * - the profile at this time could already be invisible (e.g. if the
+ * user didn't ceate a proper session (sudo) and manually activates
+ * an invisible profile. In this case, we still want to bind the
+ * lifetime, and it will disconnect after the user logs in and logs
+ * out again. NMKeepAlive takes care of that.
+ */
+ return NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY;
+}
+
/* The parent connection is ready; we can proceed realizing the device and
* progressing the device to disconencted state.
*/
@@ -4420,6 +4495,8 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
subject,
NM_ACTIVATION_TYPE_MANAGED,
nm_active_connection_get_activation_reason (active),
+ nm_active_connection_get_state_flags (active)
+ & NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY,
error);
if (!parent_ac) {
g_prefix_error (error, "%s failed to activate parent: ", nm_device_get_iface (device));
@@ -4620,6 +4697,7 @@ _new_active_connection (NMManager *self,
NMAuthSubject *subject,
NMActivationType activation_type,
NMActivationReason activation_reason,
+ NMActivationStateFlags initial_state_flags,
GError **error)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
@@ -4691,6 +4769,7 @@ _new_active_connection (NMManager *self,
parent_device,
nm_dbus_object_get_path (NM_DBUS_OBJECT (parent)),
activation_reason,
+ initial_state_flags,
subject);
}
@@ -4700,6 +4779,7 @@ _new_active_connection (NMManager *self,
subject,
activation_type,
activation_reason,
+ initial_state_flags,
device);
}
@@ -4763,6 +4843,7 @@ fail:
* @activation_type: whether to assume the connection. That is, take over gracefully,
* non-destructible.
* @activation_reason: the reason for activation
+ * @initial_state_flags: the inital state flags for the activation.
* @error: return location for an error
*
* Begins a new internally-initiated activation of @sett_conn on @device.
@@ -4784,6 +4865,7 @@ nm_manager_activate_connection (NMManager *self,
NMAuthSubject *subject,
NMActivationType activation_type,
NMActivationReason activation_reason,
+ NMActivationStateFlags initial_state_flags,
GError **error)
{
NMManagerPrivate *priv;
@@ -4837,6 +4919,7 @@ nm_manager_activate_connection (NMManager *self,
subject,
activation_type,
activation_reason,
+ initial_state_flags,
error);
if (!active)
return NULL;
@@ -5096,6 +5179,7 @@ impl_manager_activate_connection (NMDBusObject *obj,
subject,
NM_ACTIVATION_TYPE_MANAGED,
NM_ACTIVATION_REASON_USER_REQUEST,
+ _activation_bind_lifetime_to_profile_visibility (subject),
&error);
if (!active)
goto error;
@@ -5370,6 +5454,7 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj,
subject,
NM_ACTIVATION_TYPE_MANAGED,
NM_ACTIVATION_REASON_USER_REQUEST,
+ _activation_bind_lifetime_to_profile_visibility (subject),
&error);
if (!active)
goto error;
diff --git a/src/nm-manager.h b/src/nm-manager.h
index 4b159f1ebd..ecb4b0172d 100644
--- a/src/nm-manager.h
+++ b/src/nm-manager.h
@@ -175,6 +175,7 @@ NMActiveConnection *nm_manager_activate_connection (NMManager *manager,
NMAuthSubject *subject,
NMActivationType activation_type,
NMActivationReason activation_reason,
+ NMActivationStateFlags initial_state_flags,
GError **error);
gboolean nm_manager_deactivate_connection (NMManager *manager,
diff --git a/src/nm-policy.c b/src/nm-policy.c
index ab9571f6df..b9e26f604e 100644
--- a/src/nm-policy.c
+++ b/src/nm-policy.c
@@ -1284,6 +1284,7 @@ auto_activate_device (NMPolicy *self,
subject,
NM_ACTIVATION_TYPE_MANAGED,
NM_ACTIVATION_REASON_AUTOCONNECT,
+ NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY,
&error);
if (!ac) {
_LOGI (LOGD_DEVICE, "connection '%s' auto-activation failed: %s",
@@ -1674,9 +1675,14 @@ activate_secondary_connections (NMPolicy *self,
GError *error = NULL;
guint32 i;
gboolean success = TRUE;
+ NMActivationStateFlags initial_state_flags;
s_con = nm_connection_get_setting_connection (connection);
- nm_assert (s_con);
+ nm_assert (NM_IS_SETTING_CONNECTION (s_con));
+
+ /* we propagate the activation's state flags. */
+ initial_state_flags = nm_device_get_activation_state_flags (device)
+ & NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY;
for (i = 0; i < nm_setting_connection_get_num_secondaries (s_con); i++) {
NMSettingsConnection *sett_conn;
@@ -1700,7 +1706,6 @@ activate_secondary_connections (NMPolicy *self,
}
req = nm_device_get_act_request (device);
- g_assert (req);
_LOGD (LOGD_DEVICE, "activating secondary connection '%s (%s)' for base connection '%s (%s)'",
nm_settings_connection_get_id (sett_conn), sec_uuid,
@@ -1713,6 +1718,7 @@ activate_secondary_connections (NMPolicy *self,
nm_active_connection_get_subject (NM_ACTIVE_CONNECTION (req)),
NM_ACTIVATION_TYPE_MANAGED,
nm_active_connection_get_activation_reason (NM_ACTIVE_CONNECTION (req)),
+ initial_state_flags,
&error);
if (ac)
secondary_ac_list = g_slist_append (secondary_ac_list, g_object_ref (ac));
@@ -2162,6 +2168,8 @@ vpn_connection_retry_after_failure (NMVpnConnection *vpn, NMPolicy *self)
nm_active_connection_get_subject (ac),
NM_ACTIVATION_TYPE_MANAGED,
nm_active_connection_get_activation_reason (ac),
+ ( nm_active_connection_get_state_flags (ac)
+ & NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY),
&error)) {
_LOGW (LOGD_DEVICE, "VPN '%s' reconnect failed: %s",
nm_settings_connection_get_id (connection),
diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c
index 7f606c2554..d4f9a5d54b 100644
--- a/src/vpn/nm-vpn-connection.c
+++ b/src/vpn/nm-vpn-connection.c
@@ -851,6 +851,7 @@ nm_vpn_connection_new (NMSettingsConnection *settings_connection,
NMDevice *parent_device,
const char *specific_object,
NMActivationReason activation_reason,
+ NMActivationStateFlags initial_state_flags,
NMAuthSubject *subject)
{
g_return_val_if_fail (!settings_connection || NM_IS_SETTINGS_CONNECTION (settings_connection), NULL);
@@ -864,6 +865,7 @@ nm_vpn_connection_new (NMSettingsConnection *settings_connection,
NM_ACTIVE_CONNECTION_INT_SUBJECT, subject,
NM_ACTIVE_CONNECTION_INT_ACTIVATION_REASON, activation_reason,
NM_ACTIVE_CONNECTION_VPN, TRUE,
+ NM_ACTIVE_CONNECTION_STATE_FLAGS, (guint) initial_state_flags,
NULL);
}
diff --git a/src/vpn/nm-vpn-connection.h b/src/vpn/nm-vpn-connection.h
index e409cc314f..5482fb0d8b 100644
--- a/src/vpn/nm-vpn-connection.h
+++ b/src/vpn/nm-vpn-connection.h
@@ -53,6 +53,7 @@ NMVpnConnection * nm_vpn_connection_new (NMSettingsConnection *settings_connecti
NMDevice *parent_device,
const char *specific_object,
NMActivationReason activation_reason,
+ NMActivationStateFlags initial_state_flags,
NMAuthSubject *subject);
void nm_vpn_connection_activate (NMVpnConnection *self,