From c724c92f1200002aad44d5837efd260846ea2af9 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Mon, 14 Mar 2022 10:20:12 +0100 Subject: [PATCH] settings-connection: add a "plugin" argument to Update2() This will allow migrating a connection. If specified, the connection will be confined to a particular settings plugin when written back. If the plugin differs from the existing one, it will be removed from the old one. --- ...top.NetworkManager.Settings.Connection.xml | 9 ++-- src/core/devices/nm-device.c | 1 + src/core/nm-checkpoint.c | 1 + src/core/nm-manager.c | 1 + src/core/settings/nm-settings-connection.c | 43 ++++++++++++++++--- src/core/settings/nm-settings-connection.h | 1 + src/core/settings/nm-settings.c | 34 ++++++++++++++- src/core/settings/nm-settings.h | 1 + 8 files changed, 79 insertions(+), 12 deletions(-) diff --git a/introspection/org.freedesktop.NetworkManager.Settings.Connection.xml b/introspection/org.freedesktop.NetworkManager.Settings.Connection.xml index 4c6d2b1930..0ace2b7f8f 100644 --- a/introspection/org.freedesktop.NetworkManager.Settings.Connection.xml +++ b/introspection/org.freedesktop.NetworkManager.Settings.Connection.xml @@ -114,9 +114,12 @@ "0x20" (block-autoconnect), "0x40" (no-reapply). Unknown flags cause the call to fail. - @args: optional arguments dictionary, for extentibility. Currently, no - arguments are accepted. Specifying unknown keys causes the call - to fail. + @args: optional arguments dictionary, for extensibility. Currently, the + following arguments are accepted: + "plugin" (s) string that specifies the settings plugin the newly + added connection will use, such as "keyfile" or "ifcfg-rh". + Since: 1.38 + Specifying unknown or duplicate keys causes the call to fail. @result: output argument, currently no results are returned. Update the connection with new settings and properties (replacing all diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 47daa92e81..30bf86f0b3 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -3859,6 +3859,7 @@ update_external_connection(NMDevice *self) if (connection_new) { nm_settings_connection_update(settings_connection, + NULL, connection_new, NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY, NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, diff --git a/src/core/nm-checkpoint.c b/src/core/nm-checkpoint.c index 5f57809b61..1566733289 100644 --- a/src/core/nm-checkpoint.c +++ b/src/core/nm-checkpoint.c @@ -231,6 +231,7 @@ restore_and_activate_connection(NMCheckpoint *self, DeviceCheckpoint *dev_checkp persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP; nm_settings_connection_update( connection, + NULL, dev_checkpoint->settings_connection, persist_mode, sett_flags, diff --git a/src/core/nm-manager.c b/src/core/nm-manager.c index a5f3ac03f1..046fa819e9 100644 --- a/src/core/nm-manager.c +++ b/src/core/nm-manager.c @@ -3060,6 +3060,7 @@ recheck_assume_connection(NMManager *self, NMDevice *device) nm_settings_connection_update( sett_conn, + NULL, con2, NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, diff --git a/src/core/settings/nm-settings-connection.c b/src/core/settings/nm-settings-connection.c index bb670c52be..3cc2932d6e 100644 --- a/src/core/settings/nm-settings-connection.c +++ b/src/core/settings/nm-settings-connection.c @@ -623,6 +623,7 @@ _secrets_update(NMConnection *connection, gboolean nm_settings_connection_update(NMSettingsConnection *self, + const char *plugin_name, NMConnection *new_connection, NMSettingsConnectionPersistMode persist_mode, NMSettingsConnectionIntFlags sett_flags, @@ -635,6 +636,7 @@ nm_settings_connection_update(NMSettingsConnection *self, return nm_settings_update_connection(NM_SETTINGS_CONNECTION_GET_PRIVATE(self)->settings, self, + plugin_name, new_connection, persist_mode, sett_flags, @@ -852,6 +854,7 @@ nm_settings_connection_new_secrets(NMSettingsConnection *self, if (!nm_settings_connection_update( self, + NULL, new_connection ?: connection, NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, @@ -997,6 +1000,7 @@ get_secrets_done_cb(NMAgentManager *manager, } if (!nm_settings_connection_update( self, + NULL, new_connection, agent_had_system ? NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP : NM_SETTINGS_CONNECTION_PERSIST_MODE_NO_PERSIST, @@ -1426,6 +1430,7 @@ typedef struct { NMConnection *new_settings; NMSettingsUpdate2Flags flags; char *audit_args; + char *plugin_name; bool is_update2 : 1; } UpdateInfo; @@ -1453,6 +1458,7 @@ update_complete(NMSettingsConnection *self, UpdateInfo *info, GError *error) g_clear_object(&info->agent_mgr); g_clear_object(&info->new_settings); g_free(info->audit_args); + g_free(info->plugin_name); g_slice_free(UpdateInfo, info); } @@ -1589,6 +1595,7 @@ update_auth_cb(NMSettingsConnection *self, nm_settings_connection_update( self, + info->plugin_name, info->new_settings, persist_mode, (NM_FLAGS_HAS(info->flags, NM_SETTINGS_UPDATE2_FLAG_VOLATILE) @@ -1659,6 +1666,7 @@ settings_connection_update(NMSettingsConnection *self, gboolean is_update2, GDBusMethodInvocation *context, GVariant *new_settings, + const char *plugin_name, NMSettingsUpdate2Flags flags) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self); @@ -1713,6 +1721,7 @@ settings_connection_update(NMSettingsConnection *self, info->subject = subject; info->flags = flags; info->new_settings = tmp; + info->plugin_name = g_strdup(plugin_name); permission = get_update_modify_permission(nm_settings_connection_get_connection(self), tmp ?: nm_settings_connection_get_connection(self)); @@ -1741,7 +1750,12 @@ impl_settings_connection_update(NMDBusObject *obj, gs_unref_variant GVariant *settings = NULL; g_variant_get(parameters, "(@a{sa{sv}})", &settings); - settings_connection_update(self, FALSE, invocation, settings, NM_SETTINGS_UPDATE2_FLAG_TO_DISK); + settings_connection_update(self, + FALSE, + invocation, + settings, + NULL, + NM_SETTINGS_UPDATE2_FLAG_TO_DISK); } static void @@ -1761,6 +1775,7 @@ impl_settings_connection_update_unsaved(NMDBusObject *obj, FALSE, invocation, settings, + NULL, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY); } @@ -1775,7 +1790,12 @@ impl_settings_connection_save(NMDBusObject *obj, { NMSettingsConnection *self = NM_SETTINGS_CONNECTION(obj); - settings_connection_update(self, FALSE, invocation, NULL, NM_SETTINGS_UPDATE2_FLAG_TO_DISK); + settings_connection_update(self, + FALSE, + invocation, + NULL, + NULL, + NM_SETTINGS_UPDATE2_FLAG_TO_DISK); } static void @@ -1787,13 +1807,15 @@ impl_settings_connection_update2(NMDBusObject *obj, GDBusMethodInvocation *invocation, GVariant *parameters) { - NMSettingsConnection *self = NM_SETTINGS_CONNECTION(obj); - gs_unref_variant GVariant *settings = NULL; - gs_unref_variant GVariant *args = NULL; + NMSettingsConnection *self = NM_SETTINGS_CONNECTION(obj); + gs_unref_variant GVariant *settings = NULL; + gs_unref_variant GVariant *args = NULL; + gs_free char *plugin_name = NULL; guint32 flags_u; GError *error = NULL; GVariantIter iter; const char *args_name; + GVariant *args_value; NMSettingsUpdate2Flags flags; g_variant_get(parameters, "(@a{sa{sv}}u@a{sv})", &settings, &flags_u, &args); @@ -1829,7 +1851,13 @@ impl_settings_connection_update2(NMDBusObject *obj, nm_assert(g_variant_is_of_type(args, G_VARIANT_TYPE("a{sv}"))); g_variant_iter_init(&iter, args); - while (g_variant_iter_next(&iter, "{&sv}", &args_name, NULL)) { + while (g_variant_iter_next(&iter, "{&sv}", &args_name, &args_value)) { + if (plugin_name == NULL && nm_streq(args_name, "plugin") + && g_variant_is_of_type(args_value, G_VARIANT_TYPE_STRING)) { + plugin_name = g_variant_dup_string(args_value, NULL); + continue; + } + error = g_error_new(NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_INVALID_ARGUMENTS, "Unsupported argument '%s'", @@ -1838,7 +1866,7 @@ impl_settings_connection_update2(NMDBusObject *obj, return; } - settings_connection_update(self, TRUE, invocation, settings, flags); + settings_connection_update(self, TRUE, invocation, settings, plugin_name, flags); } static void @@ -2027,6 +2055,7 @@ dbus_clear_secrets_auth_cb(NMSettingsConnection *self, if (!nm_settings_connection_update( self, + NULL, connection_cloned, NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, diff --git a/src/core/settings/nm-settings-connection.h b/src/core/settings/nm-settings-connection.h index 228ccb084c..5022986bb4 100644 --- a/src/core/settings/nm-settings-connection.h +++ b/src/core/settings/nm-settings-connection.h @@ -241,6 +241,7 @@ nm_settings_connection_has_unmodified_applied_connection(NMSettingsConnection *s NMSettingCompareFlags compare_flage); gboolean nm_settings_connection_update(NMSettingsConnection *self, + const char *plugin_name, NMConnection *new_connection, NMSettingsConnectionPersistMode persist_mode, NMSettingsConnectionIntFlags sett_flags, diff --git a/src/core/settings/nm-settings.c b/src/core/settings/nm-settings.c index 7d3bce4cd6..4a27f1ef6b 100644 --- a/src/core/settings/nm-settings.c +++ b/src/core/settings/nm-settings.c @@ -236,12 +236,16 @@ _sett_conn_entry_get_conn(SettConnEntry *sett_conn_entry) * update-connection. If this parameter is omitted, then it's about what happens * when adding a new profile (add-connection). * + * @storage_check_ignore is optional, and if given then it skips this particular + * storage. + * * Returns: the conflicting storage or %NULL if there is none. */ static NMSettingsStorage * _sett_conn_entry_storage_find_conflicting_storage(SettConnEntry *sett_conn_entry, NMSettingsPlugin *target_plugin, NMSettingsStorage *storage_check_including, + NMSettingsStorage *storage_check_ignore, const GSList *plugins) { StorageData *sd; @@ -269,6 +273,12 @@ _sett_conn_entry_storage_find_conflicting_storage(SettConnEntry *sett_conn_e continue; } + if (sd->storage == storage_check_ignore) { + /* We ignore this one, because we're in the process of + * replacing it. */ + continue; + } + if (sd->storage == storage_check_including) { /* ok, the storage is the one we are about to check. All other * storages are lower priority, so there is no storage that hides @@ -1472,6 +1482,7 @@ _add_connection_to_first_plugin(NMSettings *self, gboolean shadowed_owned, NMSettingsStorage **out_new_storage, NMConnection **out_new_connection, + NMSettingsStorage *drop_storage, GError **error) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self); @@ -1506,6 +1517,7 @@ _add_connection_to_first_plugin(NMSettings *self, conflicting_storage = _sett_conn_entry_storage_find_conflicting_storage(sett_conn_entry, plugin, NULL, + drop_storage, priv->plugins); if (conflicting_storage) { /* we have a connection provided by a plugin with higher priority than the one @@ -1820,6 +1832,7 @@ nm_settings_add_connection(NMSettings *self, sett_conn_entry, nm_settings_storage_get_plugin(shadowed_storage), shadowed_storage, + NULL, priv->plugins); if (conflicting_storage) { /* We cannot add the profile as @shadowed_storage, because there is another, existing storage @@ -1853,6 +1866,7 @@ again_add_connection: FALSE, &new_storage, &new_connection, + NULL, &local); } else { success = _update_connection_to_plugin(self, @@ -1969,6 +1983,7 @@ again_delete_tombstone: gboolean nm_settings_update_connection(NMSettings *self, NMSettingsConnection *sett_conn, + const char *plugin_name, NMConnection *connection, NMSettingsConnectionPersistMode persist_mode, NMSettingsConnectionIntFlags sett_flags, @@ -2175,8 +2190,9 @@ nm_settings_update_connection(NMSettings *self, } else if (nm_settings_storage_is_keyfile_lib(cur_storage)) { /* the profile is a keyfile in /usr/lib. It cannot be overwritten, we must migrate it * from /usr/lib to /etc. */ - } else + } else { update_storage = cur_storage; + } if (new_in_memory) { if (persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY) { @@ -2195,9 +2211,22 @@ nm_settings_update_connection(NMSettings *self, } } + if (update_storage && plugin_name) { + NMSettingsPlugin *plugin = nm_settings_storage_get_plugin(update_storage); + + if (strcmp(plugin_name, nm_settings_plugin_get_plugin_name(plugin))) { + /* We're updating a connection, we're confined to a particular + * plugin, but the connection is currently using a different one. + * We need to migrate. Drop the existing storage and look out for + * a new one. */ + drop_storage = update_storage; + update_storage = NULL; + } + } + if (!update_storage) { success = _add_connection_to_first_plugin(self, - NULL, + plugin_name, sett_conn_entry, connection, new_in_memory, @@ -2206,6 +2235,7 @@ nm_settings_update_connection(NMSettings *self, new_shadowed_owned, &new_storage, &new_connection, + drop_storage, &local); } else { success = _update_connection_to_plugin(self, diff --git a/src/core/settings/nm-settings.h b/src/core/settings/nm-settings.h index 6728639f67..8747d1dcd7 100644 --- a/src/core/settings/nm-settings.h +++ b/src/core/settings/nm-settings.h @@ -101,6 +101,7 @@ gboolean nm_settings_add_connection(NMSettings *settings, gboolean nm_settings_update_connection(NMSettings *self, NMSettingsConnection *sett_conn, + const char *plugin_name, NMConnection *new_connection, NMSettingsConnectionPersistMode persist_mode, NMSettingsConnectionIntFlags sett_flags,