summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/devices/nm-device.c431
-rw-r--r--src/nm-audit-manager.h1
2 files changed, 195 insertions, 237 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index ad5a649f3c..0e5993a79c 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -6829,164 +6829,77 @@ _cleanup_ip6_pre (NMDevice *self, CleanupType cleanup_type)
addrconf6_cleanup (self);
}
+G_GNUC_NULL_TERMINATED
static gboolean
-reapply_ip4_config (NMDevice *self,
- NMConnection *old,
- gboolean reconfigure,
- GError **error)
+_hash_check_invalid_keys (GHashTable *hash, const char *setting_name, GError **error, ...)
{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
- NMSettingsConnection *connection = nm_device_get_settings_connection (self);
- NMSettingIPConfig *s_ip4 = nm_connection_get_setting_ip4_config (NM_CONNECTION (connection));
- NMSettingIPConfig *s_ip4_applied = nm_connection_get_setting_ip4_config (old);
- const char *method;
- const char *method_applied;
-
- if (!s_ip4 || !s_ip4_applied || priv->ip4_state == IP_NONE) {
- g_set_error_literal (error,
- NM_DEVICE_ERROR,
- NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
- "No IPv4 configuration to update");
- return FALSE;
- }
-
- if (!reconfigure)
- return TRUE;
-
- method = nm_setting_ip_config_get_method (s_ip4);
- method_applied = nm_setting_ip_config_get_method (s_ip4_applied);
+ va_list ap;
+ const char *key;
+ guint found_keys = 0;
- g_clear_object (&priv->con_ip4_config);
- priv->con_ip4_config = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
- nm_ip4_config_merge_setting (priv->con_ip4_config,
- nm_connection_get_setting_ip4_config (NM_CONNECTION (connection)),
- nm_device_get_ip4_route_metric (self));
+#if NM_MORE_ASSERTS > 10
+ /* Assert that the keys are unique. */
+ {
+ gs_unref_hashtable GHashTable *check_dups = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, NULL);
- if (strcmp (method, method_applied)) {
- _cleanup_ip4_pre (self, CLEANUP_TYPE_DECONFIGURE);
- priv->ip4_state = IP_WAIT;
- if (!nm_device_activate_stage3_ip4_start (self)) {
- g_set_error_literal (error,
- NM_DEVICE_ERROR,
- NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
- "Failed to apply IPv4 configuration");
- return FALSE;
+ va_start (ap, error);
+ while ((key = va_arg (ap, const char *))) {
+ if (!g_hash_table_add (check_dups, (char *) key))
+ nm_assert (FALSE);
}
- } else {
- ip4_config_merge_and_apply (self, NULL, TRUE, NULL);
- }
-
- return TRUE;
-}
-
-static gboolean
-reapply_ip6_config (NMDevice *self,
- NMConnection *old,
- gboolean reconfigure,
- GError **error)
-{
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
- NMSettingsConnection *connection = nm_device_get_settings_connection (self);
- NMSettingIPConfig *s_ip6 = nm_connection_get_setting_ip6_config (NM_CONNECTION (connection));
- NMSettingIPConfig *s_ip6_applied = nm_connection_get_setting_ip6_config (old);
- const char *method;
- const char *method_applied;
-
- if (!s_ip6 || !s_ip6_applied || priv->ip6_state == IP_NONE) {
- g_set_error_literal (error,
- NM_DEVICE_ERROR,
- NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
- "No IPv6 configuration to update");
- return FALSE;
+ va_end (ap);
+ nm_assert (g_hash_table_size (check_dups) > 0);
}
+#endif
- if (!reconfigure)
+ if (!hash || g_hash_table_size (hash) == 0)
return TRUE;
- method = nm_setting_ip_config_get_method (s_ip6);
- method_applied = nm_setting_ip_config_get_method (s_ip6_applied);
-
- g_clear_object (&priv->con_ip6_config);
- priv->con_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
- nm_ip6_config_merge_setting (priv->con_ip6_config,
- nm_connection_get_setting_ip6_config (NM_CONNECTION (connection)),
- nm_device_get_ip6_route_metric (self));
-
- if (strcmp (method, method_applied)) {
- _cleanup_ip6_pre (self, CLEANUP_TYPE_DECONFIGURE);
- priv->ip6_state = IP_WAIT;
- if (!nm_device_activate_stage3_ip6_start (self)) {
- g_set_error_literal (error,
- NM_DEVICE_ERROR,
- NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
- "Failed to apply IPv6 configuration");
- return FALSE;
- }
- } else {
- ip6_config_merge_and_apply (self, TRUE, NULL);
+ va_start (ap, error);
+ while ((key = va_arg (ap, const char *))) {
+ if (g_hash_table_contains (hash, key))
+ found_keys++;
}
+ va_end (ap);
- return TRUE;
-}
+ if (found_keys != g_hash_table_size (hash)) {
+ GHashTableIter iter;
+ const char *k = NULL;
+ const char *first_invalid_key = NULL;
-static gboolean
-reapply_connection_setting (NMDevice *self,
- NMConnection *old,
- gboolean reconfigure,
- GError **error)
-{
- NMConnection *applied_connection;
- NMSettingConnection *s_con_settings;
- NMSettingConnection *s_con_applied;
- const char *zone;
- NMMetered metered;
-
- g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
-
- applied_connection = nm_device_get_applied_connection (self);
-
- s_con_settings = nm_connection_get_setting_connection (old);
- s_con_applied = nm_connection_get_setting_connection (applied_connection);
-
- if (!reconfigure) {
- GHashTable *results = NULL;
-
- nm_setting_diff (NM_SETTING (s_con_settings),
- NM_SETTING (s_con_applied),
- NM_SETTING_COMPARE_FLAG_IGNORE_TIMESTAMP |
- NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS |
- NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY,
- FALSE,
- &results);
- if (!results)
- return TRUE;
+ if (!error)
+ return FALSE;
- g_hash_table_destroy (results);
- g_set_error_literal (error,
- NM_DEVICE_ERROR,
- NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
- "The 'connection' settings have changes that can't be reapplied");
+ g_hash_table_iter_init (&iter, hash);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &k, NULL)) {
+ va_start (ap, error);
+ while ((key = va_arg (ap, const char *))) {
+ if (!strcmp (key, k)) {
+ first_invalid_key = k;
+ break;
+ }
+ }
+ va_end (ap);
+ if (first_invalid_key)
+ break;
+ }
+ g_set_error (error,
+ NM_DEVICE_ERROR,
+ NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
+ "Can't reapply changes to '%s%s%s' setting",
+ setting_name ? : "",
+ setting_name ? "." : "",
+ first_invalid_key ? : "<UNKNOWN>");
+ g_return_val_if_fail (first_invalid_key, FALSE);
return FALSE;
}
- if (g_strcmp0 ((zone = nm_setting_connection_get_zone (s_con_settings)),
- nm_setting_connection_get_zone (s_con_applied)) != 0) {
- _LOGD (LOGD_DEVICE, "reapply setting: zone = %s%s%s", NM_PRINT_FMT_QUOTE_STRING (zone));
- nm_device_update_firewall_zone (self);
- }
-
- if ((metered = nm_setting_connection_get_metered (s_con_settings)) != nm_setting_connection_get_metered (s_con_applied)) {
- _LOGD (LOGD_DEVICE, "reapply setting: metered = %d", (int) metered);
- nm_device_update_metered (self);
- }
-
return TRUE;
}
/* reapply_connection:
- * @connection: the new connection settings to be applied
- * @flags: always zero
- * @reconfigure: %FALSE if this is a dry-run, %TRUE for an actual action
+ * @connection: the new connection settings to be applied or %NULL to reapply
+ * the current settings connection
* @error: the error if %FALSE is returned
*
* Change configuration of an already configured device if possible.
@@ -6997,23 +6910,21 @@ reapply_connection_setting (NMDevice *self,
static gboolean
reapply_connection (NMDevice *self,
NMConnection *connection,
- guint flags,
- gboolean reconfigure,
GError **error)
{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMConnection *applied = nm_device_get_applied_connection (self);
- NMConnection *old;
- GHashTable *diffs = NULL;
- GHashTableIter iter;
- const char *setting;
- gboolean success = FALSE;
+ gs_unref_object NMConnection *applied_clone = NULL;
+ gs_unref_hashtable GHashTable *diffs = NULL;
+ NMConnection *con_old, *con_new;
+ NMSettingIPConfig *s_ip4_old, *s_ip4_new;
+ NMSettingIPConfig *s_ip6_old, *s_ip6_new;
- /* No flags supported as of now. */
- if (flags != 0) {
- g_set_error (error,
- NM_DEVICE_ERROR,
- NM_DEVICE_ERROR_FAILED,
- "Invalid flags specified");
+ if (priv->state != NM_DEVICE_STATE_ACTIVATED) {
+ g_set_error_literal (error,
+ NM_DEVICE_ERROR,
+ NM_DEVICE_ERROR_NOT_ACTIVE,
+ "Device is not activated");
return FALSE;
}
@@ -7023,46 +6934,85 @@ reapply_connection (NMDevice *self,
NM_SETTING_COMPARE_FLAG_IGNORE_SECRETS,
&diffs);
- /* Everything set. */
- if (!diffs)
- return TRUE;
+ /**************************************************************************
+ * check for unsupported changes and reject to reapply
+ *************************************************************************/
+ if (!_hash_check_invalid_keys (diffs, NULL, error,
+ NM_SETTING_IP4_CONFIG_SETTING_NAME,
+ NM_SETTING_IP6_CONFIG_SETTING_NAME,
+ NM_SETTING_CONNECTION_SETTING_NAME,
+ NULL))
+ return FALSE;
+
+ if (!_hash_check_invalid_keys (diffs ? g_hash_table_lookup (diffs, NM_SETTING_CONNECTION_SETTING_NAME) : NULL,
+ NM_SETTING_CONNECTION_SETTING_NAME,
+ error,
+ NM_SETTING_CONNECTION_ZONE,
+ NM_SETTING_CONNECTION_METERED,
+ NULL))
+ return FALSE;
- old = nm_simple_connection_new_clone (applied);
- if (reconfigure)
+ _LOGD (LOGD_DEVICE, "reapply");
+
+ /**************************************************************************
+ * Update applied connection
+ *************************************************************************/
+
+ if (diffs) {
+ con_old = applied_clone = nm_simple_connection_new_clone (applied);
+ con_new = applied;
nm_connection_replace_settings_from_connection (applied, connection);
+ } else
+ con_old = con_new = applied;
- g_hash_table_iter_init (&iter, diffs);
- while (g_hash_table_iter_next (&iter, (gpointer *)&setting, NULL)) {
- if (strcmp (setting, NM_SETTING_IP4_CONFIG_SETTING_NAME) == 0) {
- if (!reapply_ip4_config (self, old, reconfigure, error))
- goto done;
- } else if (strcmp (setting, NM_SETTING_IP6_CONFIG_SETTING_NAME) == 0) {
- if (!reapply_ip6_config (self, old, reconfigure, error))
- goto done;
- } else if (strcmp (setting, NM_SETTING_CONNECTION_SETTING_NAME) == 0) {
- if (!reapply_connection_setting (self, old, reconfigure, error))
- goto done;
- } else {
- g_set_error (error,
- NM_DEVICE_ERROR,
- NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
- "Can't reapply changes to '%s' settings",
- setting);
- goto done;
- }
+ s_ip4_new = nm_connection_get_setting_ip4_config (con_new);
+ s_ip4_old = nm_connection_get_setting_ip4_config (con_old);
+ s_ip6_new = nm_connection_get_setting_ip6_config (con_new);
+ s_ip6_old = nm_connection_get_setting_ip6_config (con_old);
+
+ /**************************************************************************
+ * Reapply changes
+ *************************************************************************/
+
+ nm_device_update_firewall_zone (self);
+ nm_device_update_metered (self);
+
+ if (priv->ip4_state != IP_NONE) {
+ g_clear_object (&priv->con_ip4_config);
+ priv->con_ip4_config = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
+ nm_ip4_config_merge_setting (priv->con_ip4_config,
+ s_ip4_new,
+ nm_device_get_ip4_route_metric (self));
+
+ if (strcmp (nm_setting_ip_config_get_method (s_ip4_new),
+ nm_setting_ip_config_get_method (s_ip4_old))) {
+ _cleanup_ip4_pre (self, CLEANUP_TYPE_DECONFIGURE);
+ priv->ip4_state = IP_WAIT;
+ if (!nm_device_activate_stage3_ip4_start (self))
+ _LOGW (LOGD_IP4, "Failed to apply IPv4 configuration");
+ } else
+ ip4_config_merge_and_apply (self, NULL, TRUE, NULL);
}
- success = TRUE;
-done:
- g_hash_table_destroy (diffs);
- g_object_unref (old);
- return success;
-}
+ if (priv->ip6_state != IP_NONE) {
+ g_clear_object (&priv->con_ip6_config);
+ priv->con_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
+ nm_ip6_config_merge_setting (priv->con_ip6_config,
+ s_ip6_new,
+ nm_device_get_ip6_route_metric (self));
-typedef struct {
- NMConnection *connection;
- guint flags;
-} ReapplyInfo;
+ if (strcmp (nm_setting_ip_config_get_method (s_ip6_new),
+ nm_setting_ip_config_get_method (s_ip6_old))) {
+ _cleanup_ip6_pre (self, CLEANUP_TYPE_DECONFIGURE);
+ priv->ip6_state = IP_WAIT;
+ if (!nm_device_activate_stage3_ip6_start (self))
+ _LOGW (LOGD_IP6, "Failed to apply IPv6 configuration");
+ } else
+ ip6_config_merge_and_apply (self, TRUE, NULL);
+ }
+
+ return TRUE;
+}
static void
reapply_cb (NMDevice *self,
@@ -7071,46 +7021,25 @@ reapply_cb (NMDevice *self,
GError *error,
gpointer user_data)
{
- ReapplyInfo *info = (ReapplyInfo *)user_data;
- NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ gs_unref_object NMConnection *connection = NM_CONNECTION (user_data);
GError *local = NULL;
if (error) {
+ nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, subject, error->message);
g_dbus_method_invocation_return_gerror (context, error);
- goto out;
- }
-
- /* Authorized */
- if (priv->state != NM_DEVICE_STATE_ACTIVATED) {
- local = g_error_new_literal (NM_DEVICE_ERROR,
- NM_DEVICE_ERROR_NOT_ACTIVE,
- "Device is not activated");
- g_dbus_method_invocation_return_gerror (context, local);
- g_error_free (local);
- goto out;
+ return;
}
if (!reapply_connection (self,
- info->connection,
- info->flags,
- FALSE,
+ connection ? : (NMConnection *) nm_device_get_settings_connection (self),
&local)) {
- /* The dry-run check failed, pityfully. */
- g_dbus_method_invocation_return_gerror (context, local);
- g_error_free (local);
- goto out;
+ nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, subject, local->message);
+ g_dbus_method_invocation_take_error (context, local);
+ local = NULL;
+ } else {
+ nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, TRUE, subject, NULL);
+ g_dbus_method_invocation_return_value (context, NULL);
}
-
- reapply_connection (self,
- info->connection,
- info->flags,
- TRUE,
- &local);
- g_dbus_method_invocation_return_value (context, NULL);
-
-out:
- g_object_unref (info->connection);
- g_slice_free (ReapplyInfo, info);
}
static void
@@ -7119,17 +7048,27 @@ impl_device_reapply (NMDevice *self,
GVariant *settings,
guint flags)
{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
NMSettingsConnection *settings_connection;
- NMConnection *connection;
+ NMConnection *connection = NULL;
GError *error = NULL;
- ReapplyInfo *info;
- if (NM_DEVICE_GET_PRIVATE (self)->act_request == NULL) {
+ /* No flags supported as of now. */
+ if (flags != 0) {
error = g_error_new_literal (NM_DEVICE_ERROR,
NM_DEVICE_ERROR_NOT_ACTIVE,
- "This device is not active");
- g_dbus_method_invocation_return_gerror (context, error);
- g_error_free (error);
+ "Invalid flags specified");
+ nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, context, error->message);
+ g_dbus_method_invocation_take_error (context, error);
+ return;
+ }
+
+ if (priv->state != NM_DEVICE_STATE_ACTIVATED) {
+ error = g_error_new_literal (NM_DEVICE_ERROR,
+ NM_DEVICE_ERROR_NOT_ACTIVE,
+ "Device is not activated");
+ nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, context, error->message);
+ g_dbus_method_invocation_take_error (context, error);
return;
}
@@ -7141,20 +7080,13 @@ impl_device_reapply (NMDevice *self,
connection = nm_simple_connection_new_from_dbus (settings, &error);
if (!connection) {
g_prefix_error (&error, "The settings specified are invalid: ");
- g_dbus_method_invocation_return_gerror (context, error);
- g_error_free (error);
+ nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, context, error->message);
+ g_dbus_method_invocation_take_error (context, error);
return;
}
nm_connection_clear_secrets (connection);
- } else {
- /* Just reuse whatever is active already. */
- connection = NM_CONNECTION (g_object_ref (settings_connection));
}
- info = g_slice_new0 (ReapplyInfo);
- info->connection = connection;
- info->flags = flags;
-
/* Ask the manager to authenticate this request for us */
g_signal_emit (self, signals[AUTH_REQUEST], 0,
context,
@@ -7162,7 +7094,7 @@ impl_device_reapply (NMDevice *self,
NM_AUTH_PERMISSION_NETWORK_CONTROL,
TRUE,
reapply_cb,
- info);
+ connection);
}
static void
@@ -8851,9 +8783,13 @@ nm_device_set_dhcp_anycast_address (NMDevice *self, const char *addr)
void
nm_device_reapply_settings_immediately (NMDevice *self)
{
- NMConnection *applied_connection, *old_applied;
+ NMConnection *applied_connection;
NMSettingsConnection *settings_connection;
NMDeviceState state;
+ NMSettingConnection *s_con_settings;
+ NMSettingConnection *s_con_applied;
+ const char *zone;
+ NMMetered metered;
g_return_if_fail (NM_IS_DEVICE (self));
@@ -8870,10 +8806,31 @@ nm_device_reapply_settings_immediately (NMDevice *self)
NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY))
return;
- old_applied = nm_simple_connection_new_clone (applied_connection);
- nm_connection_replace_settings_from_connection (applied_connection, NM_CONNECTION (settings_connection));
- reapply_connection_setting (self, old_applied, TRUE, NULL);
- g_object_unref (old_applied);
+ s_con_settings = nm_connection_get_setting_connection ((NMConnection *) settings_connection);
+ s_con_applied = nm_connection_get_setting_connection (applied_connection);
+
+ if (g_strcmp0 ((zone = nm_setting_connection_get_zone (s_con_settings)),
+ nm_setting_connection_get_zone (s_con_applied)) != 0) {
+
+ _LOGD (LOGD_DEVICE, "reapply setting: zone = %s%s%s", NM_PRINT_FMT_QUOTE_STRING (zone));
+
+ g_object_set (G_OBJECT (s_con_applied),
+ NM_SETTING_CONNECTION_ZONE, zone,
+ NULL);
+
+ nm_device_update_firewall_zone (self);
+ }
+
+ if ((metered = nm_setting_connection_get_metered (s_con_settings)) != nm_setting_connection_get_metered (s_con_applied)) {
+
+ _LOGD (LOGD_DEVICE, "reapply setting: metered = %d", (int) metered);
+
+ g_object_set (G_OBJECT (s_con_applied),
+ NM_SETTING_CONNECTION_METERED, metered,
+ NULL);
+
+ nm_device_update_metered (self);
+ }
}
void
diff --git a/src/nm-audit-manager.h b/src/nm-audit-manager.h
index a3f7bc72f9..ed53be6921 100644
--- a/src/nm-audit-manager.h
+++ b/src/nm-audit-manager.h
@@ -61,6 +61,7 @@ typedef struct {
#define NM_AUDIT_OP_DEVICE_DISCONNECT "device-disconnect"
#define NM_AUDIT_OP_DEVICE_DELETE "device-delete"
#define NM_AUDIT_OP_DEVICE_MANAGED "device-managed"
+#define NM_AUDIT_OP_DEVICE_REAPPLY "device-reapply"
GType nm_audit_manager_get_type (void);
NMAuditManager *nm_audit_manager_get (void);