diff --git a/introspection/org.freedesktop.NetworkManager.Settings.Connection.xml b/introspection/org.freedesktop.NetworkManager.Settings.Connection.xml index a9240ec10..9b876e75d 100644 --- a/introspection/org.freedesktop.NetworkManager.Settings.Connection.xml +++ b/introspection/org.freedesktop.NetworkManager.Settings.Connection.xml @@ -164,6 +164,10 @@ The settings plugin the connection will be migrated to such as "keyfile" or "ifcfg-rh". Since 1.38 + version-id: + If specified, the update request is rejected if the + profile's version-id does not match. This can be used to catch concurrent + modifications. Zero means no version check.Since 1.44 diff --git a/src/core/settings/nm-settings-connection.c b/src/core/settings/nm-settings-connection.c index d0725a704..32911f16e 100644 --- a/src/core/settings/nm-settings-connection.c +++ b/src/core/settings/nm-settings-connection.c @@ -1443,6 +1443,7 @@ typedef struct { NMSettingsUpdate2Flags flags; char *audit_args; char *plugin_name; + guint64 version_id; bool is_update2 : 1; } UpdateInfo; @@ -1492,6 +1493,16 @@ update_auth_cb(NMSettingsConnection *self, priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self); + if (info->version_id != 0 && info->version_id != priv->version_id) { + g_set_error_literal(&local, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_VERSION_ID_MISMATCH, + "Update failed because profile changed in the meantime and the " + "version-id mismatches"); + error = local; + goto out; + } + if (info->new_settings) { if (!_nm_connection_aggregate(info->new_settings, NM_CONNECTION_AGGREGATE_ANY_SECRETS, @@ -1639,6 +1650,7 @@ settings_connection_update(NMSettingsConnection *self, GDBusMethodInvocation *context, GVariant *new_settings, const char *plugin_name, + guint64 version_id, NMSettingsUpdate2Flags flags) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self); @@ -1695,6 +1707,7 @@ settings_connection_update(NMSettingsConnection *self, .flags = flags, .new_settings = tmp, .plugin_name = g_strdup(plugin_name), + .version_id = version_id, }; permission = get_update_modify_permission(nm_settings_connection_get_connection(self), @@ -1729,6 +1742,7 @@ impl_settings_connection_update(NMDBusObject *obj, invocation, settings, NULL, + 0, NM_SETTINGS_UPDATE2_FLAG_TO_DISK); } @@ -1750,6 +1764,7 @@ impl_settings_connection_update_unsaved(NMDBusObject *obj, invocation, settings, NULL, + 0, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY); } @@ -1769,6 +1784,7 @@ impl_settings_connection_save(NMDBusObject *obj, invocation, NULL, NULL, + 0, NM_SETTINGS_UPDATE2_FLAG_TO_DISK); } @@ -1785,6 +1801,7 @@ impl_settings_connection_update2(NMDBusObject *obj, gs_unref_variant GVariant *settings = NULL; gs_unref_variant GVariant *args = NULL; gs_free char *plugin_name = NULL; + guint64 version_id = 0; guint32 flags_u; GError *error = NULL; GVariantIter iter; @@ -1831,6 +1848,11 @@ impl_settings_connection_update2(NMDBusObject *obj, plugin_name = g_variant_dup_string(args_value, NULL); continue; } + if (nm_streq(args_name, "version-id") + && g_variant_is_of_type(args_value, G_VARIANT_TYPE_UINT64)) { + version_id = g_variant_get_uint64(args_value); + continue; + } error = g_error_new(NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_ARGUMENTS, @@ -1840,7 +1862,7 @@ impl_settings_connection_update2(NMDBusObject *obj, return; } - settings_connection_update(self, TRUE, invocation, settings, plugin_name, flags); + settings_connection_update(self, TRUE, invocation, settings, plugin_name, version_id, flags); } static void diff --git a/src/libnm-core-public/nm-errors.h b/src/libnm-core-public/nm-errors.h index 639c508e3..a4d69c31a 100644 --- a/src/libnm-core-public/nm-errors.h +++ b/src/libnm-core-public/nm-errors.h @@ -250,6 +250,9 @@ GQuark nm_secret_agent_error_quark(void); * @NM_SETTINGS_ERROR_UUID_EXISTS: a connection with that UUID already exists * @NM_SETTINGS_ERROR_INVALID_HOSTNAME: attempted to set an invalid hostname * @NM_SETTINGS_ERROR_INVALID_ARGUMENTS: invalid arguments + * @NM_SETTINGS_ERROR_VERSION_ID_MISMATCH: The profile's VersionId mismatched + * and the update is rejected. See the "version-id" argument to Update2() + * method. Since 1.44. * * Errors related to the settings/persistent configuration interface of * NetworkManager. @@ -267,6 +270,7 @@ typedef enum { NM_SETTINGS_ERROR_UUID_EXISTS, /*< nick=UuidExists >*/ NM_SETTINGS_ERROR_INVALID_HOSTNAME, /*< nick=InvalidHostname >*/ NM_SETTINGS_ERROR_INVALID_ARGUMENTS, /*< nick=InvalidArguments >*/ + NM_SETTINGS_ERROR_VERSION_ID_MISMATCH, /*< nick=VersionIdMismatch >*/ } NMSettingsError; GQuark nm_settings_error_quark(void);