diff options
| author | Michael Biebl <biebl@debian.org> | 2023-08-09 21:55:35 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2023-08-09 21:55:35 +0200 |
| commit | 05e4a733f2141995181a551854d5df929f084adf (patch) | |
| tree | 83bb937740a6667525ba0df046748ecaa829c269 /src/core/settings | |
| parent | 14b0f3a9dc9ea90d60a3b057350fd4d637dc021a (diff) | |
New upstream version 1.44.0 upstream/1.44.0
Diffstat (limited to 'src/core/settings')
| -rw-r--r-- | src/core/settings/nm-secret-agent.c | 2 | ||||
| -rw-r--r-- | src/core/settings/nm-settings-connection.c | 321 | ||||
| -rw-r--r-- | src/core/settings/nm-settings-connection.h | 59 | ||||
| -rw-r--r-- | src/core/settings/nm-settings.c | 137 | ||||
| -rw-r--r-- | src/core/settings/nm-settings.h | 2 | ||||
| -rw-r--r-- | src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c | 16 | ||||
| -rw-r--r-- | src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 28 | ||||
| -rw-r--r-- | src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c | 1 | ||||
| -rw-r--r-- | src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h | 2 | ||||
| -rw-r--r-- | src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 26 | ||||
| -rw-r--r-- | src/core/settings/plugins/ifcfg-rh/shvar.c | 23 | ||||
| -rw-r--r-- | src/core/settings/plugins/keyfile/nms-keyfile-plugin.c | 60 | ||||
| -rw-r--r-- | src/core/settings/plugins/keyfile/nms-keyfile-writer.c | 31 | ||||
| -rw-r--r-- | src/core/settings/plugins/keyfile/nms-keyfile-writer.h | 18 | ||||
| -rw-r--r-- | src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c | 16 |
15 files changed, 457 insertions, 285 deletions
diff --git a/src/core/settings/nm-secret-agent.c b/src/core/settings/nm-secret-agent.c index a3df4497..bb300345 100644 --- a/src/core/settings/nm-secret-agent.c +++ b/src/core/settings/nm-secret-agent.c @@ -463,7 +463,7 @@ _call_cancel_cb(GObject *source, GAsyncResult *result, gpointer user_data) * nm_secret_agent_cancel_call: * @self: the #NMSecretAgent instance for the @call_id. * Maybe be %NULL if @call_id is %NULL. - * @call_id: (allow-none): the call id to cancel. May be %NULL for convenience, + * @call_id: (nullable): the call id to cancel. May be %NULL for convenience, * in which case it does nothing. * * It is an error to pass an invalid @call_id or a @call_id for an operation diff --git a/src/core/settings/nm-settings-connection.c b/src/core/settings/nm-settings-connection.c index 024c0009..176cc2c2 100644 --- a/src/core/settings/nm-settings-connection.c +++ b/src/core/settings/nm-settings-connection.c @@ -24,13 +24,10 @@ #include "libnm-core-intern/nm-core-internal.h" #include "nm-audit-manager.h" #include "nm-settings.h" +#include "nm-manager.h" #include "nm-dbus-manager.h" #include "settings/plugins/keyfile/nms-keyfile-storage.h" -#define AUTOCONNECT_RETRIES_UNSET -2 -#define AUTOCONNECT_RETRIES_FOREVER -1 -#define AUTOCONNECT_RESET_RETRIES_TIMER 300 - #define SEEN_BSSIDS_MAX 30 #define _NM_SETTINGS_UPDATE2_FLAG_ALL_PERSIST_MODES \ @@ -112,7 +109,11 @@ _seen_bssids_hash_new(void) /*****************************************************************************/ -NM_GOBJECT_PROPERTIES_DEFINE(NMSettingsConnection, PROP_UNSAVED, PROP_FLAGS, PROP_FILENAME, ); +NM_GOBJECT_PROPERTIES_DEFINE(NMSettingsConnection, + PROP_VERSION_ID, + PROP_UNSAVED, + PROP_FLAGS, + PROP_FILENAME, ); enum { UPDATED_INTERNAL, FLAGS_CHANGED, LAST_SIGNAL }; @@ -159,9 +160,7 @@ typedef struct _NMSettingsConnectionPrivate { guint64 last_secret_agent_version_id; - int autoconnect_retries; - - gint32 autoconnect_retries_blocked_until; + guint64 version_id; bool timestamp_set : 1; @@ -227,6 +226,22 @@ static guint _get_seen_bssids(NMSettingsConnection *self, /*****************************************************************************/ +NMSettings * +nm_settings_connection_get_settings(NMSettingsConnection *self) +{ + g_return_val_if_fail(NM_IS_SETTINGS_CONNECTION(self), NULL); + + return NM_SETTINGS_CONNECTION_GET_PRIVATE(self)->settings; +} + +NMManager * +nm_settings_connection_get_manager(NMSettingsConnection *self) +{ + return nm_settings_get_manager(nm_settings_connection_get_settings(self)); +} + +/*****************************************************************************/ + NMDevice * nm_settings_connection_default_wired_get_device(NMSettingsConnection *self) { @@ -361,6 +376,20 @@ nm_settings_connection_get_connection(NMSettingsConnection *self) return NM_SETTINGS_CONNECTION_GET_PRIVATE(self)->connection; } +gpointer +nm_settings_connection_get_setting(NMSettingsConnection *self, NMMetaSettingType meta_type) +{ + NMConnection *connection; + + nm_assert(NM_IS_SETTINGS_CONNECTION(self)); + + connection = NM_SETTINGS_CONNECTION_GET_PRIVATE(self)->connection; + + nm_assert(NM_IS_SIMPLE_CONNECTION(connection)); + + return _nm_connection_get_setting_by_metatype_unsafe(connection, meta_type); +} + void _nm_settings_connection_set_connection(NMSettingsConnection *self, NMConnection *new_connection, @@ -1049,7 +1078,7 @@ get_secrets_idle_cb(NMSettingsConnectionCallId *call_id) /** * nm_settings_connection_get_secrets: * @self: the #NMSettingsConnection - * @applied_connection: (allow-none): if provided, only request secrets + * @applied_connection: (nullable): if provided, only request secrets * if @self equals to @applied_connection. Also, update the secrets * in the @applied_connection. * @subject: the #NMAuthSubject originating the request @@ -1414,6 +1443,7 @@ typedef struct { NMSettingsUpdate2Flags flags; char *audit_args; char *plugin_name; + guint64 version_id; bool is_update2 : 1; } UpdateInfo; @@ -1442,53 +1472,7 @@ update_complete(NMSettingsConnection *self, UpdateInfo *info, GError *error) g_clear_object(&info->new_settings); g_free(info->audit_args); g_free(info->plugin_name); - g_slice_free(UpdateInfo, info); -} - -static int -_autoconnect_retries_initial(NMSettingsConnection *self) -{ - NMSettingConnection *s_con; - int retries = -1; - - s_con = nm_connection_get_setting_connection(nm_settings_connection_get_connection(self)); - if (s_con) - retries = nm_setting_connection_get_autoconnect_retries(s_con); - - /* -1 means 'default' */ - if (retries == -1) - retries = nm_config_data_get_autoconnect_retries_default(NM_CONFIG_GET_DATA); - - /* 0 means 'forever', which is translated to a retry count of -1 */ - if (retries == 0) - retries = AUTOCONNECT_RETRIES_FOREVER; - - nm_assert(retries == AUTOCONNECT_RETRIES_FOREVER || retries >= 0); - return retries; -} - -static void -_autoconnect_retries_set(NMSettingsConnection *self, int retries, gboolean is_reset) -{ - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self); - - g_return_if_fail(retries == AUTOCONNECT_RETRIES_FOREVER || retries >= 0); - - if (priv->autoconnect_retries != retries) { - _LOGT("autoconnect: retries set %d%s", retries, is_reset ? " (reset)" : ""); - priv->autoconnect_retries = retries; - } - - if (retries) - priv->autoconnect_retries_blocked_until = 0; - else { - /* NOTE: the blocked time must be identical for all connections, otherwise - * the tracking of resetting the retry count in NMPolicy needs adjustment - * in _connection_autoconnect_retries_set() (as it would need to re-evaluate - * the next-timeout every time a connection gets blocked). */ - priv->autoconnect_retries_blocked_until = - nm_utils_get_monotonic_timestamp_sec() + AUTOCONNECT_RESET_RETRIES_TIMER; - } + nm_g_slice_free(info); } static void @@ -1502,14 +1486,23 @@ update_auth_cb(NMSettingsConnection *self, UpdateInfo *info = data; gs_free_error GError *local = NULL; NMSettingsConnectionPersistMode persist_mode; + gs_unref_object NMConnection *for_agent = NULL; - if (error) { - update_complete(self, info, error); - return; - } + if (error) + goto out; 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, @@ -1539,10 +1532,13 @@ update_auth_cb(NMSettingsConnection *self, /* New secrets, allow autoconnection again */ if (nm_settings_connection_autoconnect_blocked_reason_set( self, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, + NM_SETTINGS_AUTOCONNECT_BLOCKED_REASON_NO_SECRETS, FALSE) && !nm_settings_connection_autoconnect_blocked_reason_get(self)) - nm_settings_connection_autoconnect_retries_reset(self); + nm_manager_devcon_autoconnect_retries_reset( + nm_settings_connection_get_manager(self), + NULL, + self); } } @@ -1586,10 +1582,9 @@ update_auth_cb(NMSettingsConnection *self, : NM_SETTINGS_CONNECTION_INT_FLAGS_NONE), NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED | NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE | NM_SETTINGS_CONNECTION_INT_FLAGS_EXTERNAL, - NM_SETTINGS_CONNECTION_UPDATE_REASON_FORCE_RENAME - | (NM_FLAGS_HAS(info->flags, NM_SETTINGS_UPDATE2_FLAG_NO_REAPPLY) - ? NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE - : NM_SETTINGS_CONNECTION_UPDATE_REASON_REAPPLY_PARTIAL) + (NM_FLAGS_HAS(info->flags, NM_SETTINGS_UPDATE2_FLAG_NO_REAPPLY) + ? NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE + : NM_SETTINGS_CONNECTION_UPDATE_REASON_REAPPLY_PARTIAL) | NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_SYSTEM_SECRETS | NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_AGENT_SECRETS | NM_SETTINGS_CONNECTION_UPDATE_REASON_UPDATE_NON_SECRET @@ -1599,25 +1594,29 @@ update_auth_cb(NMSettingsConnection *self, "update-from-dbus", &local); - if (!local) { - gs_unref_object NMConnection *for_agent = NULL; - - /* Dupe the connection so we can clear out non-agent-owned secrets, - * as agent-owned secrets are the only ones we send back to be saved. - * Only send secrets to agents of the same UID that called update too. - */ - for_agent = nm_simple_connection_new_clone(nm_settings_connection_get_connection(self)); - _nm_connection_clear_secrets_by_secret_flags(for_agent, NM_SETTING_SECRET_FLAG_AGENT_OWNED); - nm_agent_manager_save_secrets(info->agent_mgr, - nm_dbus_object_get_path(NM_DBUS_OBJECT(self)), - for_agent, - info->subject); + if (local) { + error = local; + goto out; } + /* Dupe the connection so we can clear out non-agent-owned secrets, + * as agent-owned secrets are the only ones we send back to be saved. + * Only send secrets to agents of the same UID that called update too. + */ + for_agent = nm_simple_connection_new_clone(nm_settings_connection_get_connection(self)); + _nm_connection_clear_secrets_by_secret_flags(for_agent, NM_SETTING_SECRET_FLAG_AGENT_OWNED); + nm_agent_manager_save_secrets(info->agent_mgr, + nm_dbus_object_get_path(NM_DBUS_OBJECT(self)), + for_agent, + info->subject); + /* Reset auto retries back to default since connection was updated */ - nm_settings_connection_autoconnect_retries_reset(self); + nm_manager_devcon_autoconnect_retries_reset(nm_settings_connection_get_manager(self), + NULL, + self); - update_complete(self, info, local); +out: + update_complete(self, info, error); } static const char * @@ -1650,6 +1649,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); @@ -1697,14 +1697,17 @@ settings_connection_update(NMSettingsConnection *self, &error)) goto error; - info = g_slice_new0(UpdateInfo); - info->is_update2 = is_update2; - info->context = context; - info->agent_mgr = g_object_ref(priv->agent_mgr); - info->subject = subject; - info->flags = flags; - info->new_settings = tmp; - info->plugin_name = g_strdup(plugin_name); + info = g_slice_new(UpdateInfo); + *info = (UpdateInfo){ + .is_update2 = is_update2, + .context = context, + .agent_mgr = g_object_ref(priv->agent_mgr), + .subject = subject, + .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), tmp ?: nm_settings_connection_get_connection(self)); @@ -1738,6 +1741,7 @@ impl_settings_connection_update(NMDBusObject *obj, invocation, settings, NULL, + 0, NM_SETTINGS_UPDATE2_FLAG_TO_DISK); } @@ -1759,6 +1763,7 @@ impl_settings_connection_update_unsaved(NMDBusObject *obj, invocation, settings, NULL, + 0, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY); } @@ -1778,6 +1783,7 @@ impl_settings_connection_save(NMDBusObject *obj, invocation, NULL, NULL, + 0, NM_SETTINGS_UPDATE2_FLAG_TO_DISK); } @@ -1794,6 +1800,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; @@ -1840,6 +1847,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, @@ -1849,7 +1861,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 @@ -2542,56 +2554,6 @@ nm_settings_connection_get_num_seen_bssids(NMSettingsConnection *self) /*****************************************************************************/ -/** - * nm_settings_connection_autoconnect_retries_get: - * @self: the settings connection - * - * Returns the number of autoconnect retries left. If the value is - * not yet set, initialize it with the value from the connection or - * with the global default. - */ -int -nm_settings_connection_autoconnect_retries_get(NMSettingsConnection *self) -{ - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self); - - if (G_UNLIKELY(priv->autoconnect_retries == AUTOCONNECT_RETRIES_UNSET)) { - _autoconnect_retries_set(self, _autoconnect_retries_initial(self), TRUE); - } - return priv->autoconnect_retries; -} - -void -nm_settings_connection_autoconnect_retries_set(NMSettingsConnection *self, int retries) -{ - g_return_if_fail(NM_IS_SETTINGS_CONNECTION(self)); - g_return_if_fail(retries >= 0); - - _autoconnect_retries_set(self, retries, FALSE); -} - -void -nm_settings_connection_autoconnect_retries_reset(NMSettingsConnection *self) -{ - g_return_if_fail(NM_IS_SETTINGS_CONNECTION(self)); - - _autoconnect_retries_set(self, _autoconnect_retries_initial(self), TRUE); -} - -gint32 -nm_settings_connection_autoconnect_retries_blocked_until(NMSettingsConnection *self) -{ - return NM_SETTINGS_CONNECTION_GET_PRIVATE(self)->autoconnect_retries_blocked_until; -} - -static NM_UTILS_FLAGS2STR_DEFINE( - _autoconnect_blocked_reason_to_string, - NMSettingsAutoconnectBlockedReason, - NM_UTILS_FLAGS2STR(NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE, "none"), - NM_UTILS_FLAGS2STR(NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, "user-request"), - NM_UTILS_FLAGS2STR(NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED, "failed"), - NM_UTILS_FLAGS2STR(NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS, "no-secrets"), ); - NMSettingsAutoconnectBlockedReason nm_settings_connection_autoconnect_blocked_reason_get(NMSettingsConnection *self) { @@ -2599,25 +2561,41 @@ nm_settings_connection_autoconnect_blocked_reason_get(NMSettingsConnection *self } gboolean -nm_settings_connection_autoconnect_blocked_reason_set_full(NMSettingsConnection *self, - NMSettingsAutoconnectBlockedReason mask, - NMSettingsAutoconnectBlockedReason value) +nm_settings_connection_autoconnect_blocked_reason_set(NMSettingsConnection *self, + NMSettingsAutoconnectBlockedReason reason, + gboolean set) { NMSettingsAutoconnectBlockedReason v; NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self); - char buf[100]; + char buf1[200]; + char buf2[200]; - nm_assert(mask); - nm_assert(!NM_FLAGS_ANY(value, ~mask)); + nm_assert(reason != NM_SETTINGS_AUTOCONNECT_BLOCKED_REASON_NONE); + nm_assert(!NM_FLAGS_ANY(reason, + ~(NM_SETTINGS_AUTOCONNECT_BLOCKED_REASON_USER_REQUEST + | NM_SETTINGS_AUTOCONNECT_BLOCKED_REASON_NO_SECRETS))); v = priv->autoconnect_blocked_reason; - v = (v & ~mask) | (value & mask); + v = NM_FLAGS_ASSIGN(v, reason, set); if (priv->autoconnect_blocked_reason == v) return FALSE; - _LOGT("autoconnect: blocked reason: %s", - _autoconnect_blocked_reason_to_string(v, buf, sizeof(buf))); + if (set) { + _LOGT("block-autoconnect: profile: blocked with reason %s (%s %s)", + nm_settings_autoconnect_blocked_reason_to_string(v, buf1, sizeof(buf1)), + "just blocked", + nm_settings_autoconnect_blocked_reason_to_string(reason, buf2, sizeof(buf2))); + } else if (v != NM_SETTINGS_AUTOCONNECT_BLOCKED_REASON_NONE) { + _LOGT("block-autoconnect: profile: blocked with reason %s (%s %s)", + nm_settings_autoconnect_blocked_reason_to_string(v, buf1, sizeof(buf1)), + "just unblocked", + nm_settings_autoconnect_blocked_reason_to_string(reason, buf2, sizeof(buf2))); + } else { + _LOGT("block-autoconnect: profile: not blocked (unblocked %s)", + nm_settings_autoconnect_blocked_reason_to_string(reason, buf1, sizeof(buf1))); + } + priv->autoconnect_blocked_reason = v; return TRUE; } @@ -2632,9 +2610,7 @@ nm_settings_connection_autoconnect_is_blocked(NMSettingsConnection *self) priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self); - if (priv->autoconnect_blocked_reason != NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE) - return TRUE; - if (priv->autoconnect_retries == 0) + if (priv->autoconnect_blocked_reason != NM_SETTINGS_AUTOCONNECT_BLOCKED_REASON_NONE) return TRUE; flags = priv->flags; @@ -2693,6 +2669,23 @@ nm_settings_connection_get_uuid(NMSettingsConnection *self) return uuid; } +guint64 +nm_settings_connection_get_version_id(NMSettingsConnection *self) +{ + g_return_val_if_fail(NM_IS_SETTINGS_CONNECTION(self), 0); + + return NM_SETTINGS_CONNECTION_GET_PRIVATE(self)->version_id; +} + +void +nm_settings_connection_bump_version_id(NMSettingsConnection *self) +{ + g_return_if_fail(NM_IS_SETTINGS_CONNECTION(self)); + + NM_SETTINGS_CONNECTION_GET_PRIVATE(self)->version_id++; + _notify(self, PROP_VERSION_ID); +} + const char * nm_settings_connection_get_connection_type(NMSettingsConnection *self) { @@ -2716,9 +2709,13 @@ _nm_settings_connection_cleanup_after_remove(NMSettingsConnection *self) static void get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMSettingsConnection *self = NM_SETTINGS_CONNECTION(object); + NMSettingsConnection *self = NM_SETTINGS_CONNECTION(object); + NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self); switch (prop_id) { + case PROP_VERSION_ID: + g_value_set_uint64(value, priv->version_id); + break; case PROP_UNSAVED: g_value_set_boolean(value, nm_settings_connection_get_unsaved(self)); break; @@ -2748,6 +2745,7 @@ nm_settings_connection_init(NMSettingsConnection *self) self->_priv = priv; c_list_init(&self->_connections_lst); + c_list_init(&self->devcon_con_lst_head); c_list_init(&priv->seen_bssids_lst_head); c_list_init(&priv->call_ids_lst_head); c_list_init(&priv->auth_lst_head); @@ -2755,7 +2753,7 @@ nm_settings_connection_init(NMSettingsConnection *self) priv->agent_mgr = g_object_ref(nm_agent_manager_get()); priv->settings = g_object_ref(nm_settings_get()); - priv->autoconnect_retries = AUTOCONNECT_RETRIES_UNSET; + priv->version_id = 1; } NMSettingsConnection * @@ -2776,6 +2774,7 @@ dispose(GObject *object) nm_assert(!priv->default_wired_device); nm_assert(c_list_is_empty(&self->_connections_lst)); + nm_assert(c_list_is_empty(&self->devcon_con_lst_head)); nm_assert(c_list_is_empty(&priv->auth_lst_head)); /* Cancel in-progress secrets requests */ @@ -2868,7 +2867,10 @@ static const NMDBusInterfaceInfoExtended interface_info_settings_connection = { NM_SETTINGS_CONNECTION_FLAGS), NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("Filename", "s", - NM_SETTINGS_CONNECTION_FILENAME), ), ), + NM_SETTINGS_CONNECTION_FILENAME), + NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE("VersionId", + "t", + NM_SETTINGS_CONNECTION_VERSION_ID), ), ), }; static void @@ -2886,6 +2888,15 @@ nm_settings_connection_class_init(NMSettingsConnectionClass *klass) object_class->dispose = dispose; object_class->get_property = get_property; + obj_properties[PROP_VERSION_ID] = + g_param_spec_uint64(NM_SETTINGS_CONNECTION_VERSION_ID, + "", + "", + 0, + G_MAXUINT64, + 0, + G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); + obj_properties[PROP_UNSAVED] = g_param_spec_boolean(NM_SETTINGS_CONNECTION_UNSAVED, "", "", diff --git a/src/core/settings/nm-settings-connection.h b/src/core/settings/nm-settings-connection.h index fce7497c..835a978e 100644 --- a/src/core/settings/nm-settings-connection.h +++ b/src/core/settings/nm-settings-connection.h @@ -7,8 +7,11 @@ #ifndef __NETWORKMANAGER_SETTINGS_CONNECTION_H__ #define __NETWORKMANAGER_SETTINGS_CONNECTION_H__ +#include "libnm-core-intern/nm-meta-setting-base.h" + #include "nm-dbus-object.h" #include "nm-connection.h" +#include "NetworkManagerUtils.h" #include "nm-settings-storage.h" @@ -138,9 +141,10 @@ typedef enum { #define NM_SETTINGS_CONNECTION_FLAGS_CHANGED "flags-changed" /* Properties */ -#define NM_SETTINGS_CONNECTION_UNSAVED "unsaved" -#define NM_SETTINGS_CONNECTION_FLAGS "flags" -#define NM_SETTINGS_CONNECTION_FILENAME "filename" +#define NM_SETTINGS_CONNECTION_UNSAVED "unsaved" +#define NM_SETTINGS_CONNECTION_VERSION_ID "version-id" +#define NM_SETTINGS_CONNECTION_FLAGS "flags" +#define NM_SETTINGS_CONNECTION_FILENAME "filename" /** * NMSettingsConnectionIntFlags: @@ -188,19 +192,6 @@ typedef enum _NMSettingsConnectionIntFlags { _NM_SETTINGS_CONNECTION_INT_FLAGS_ALL = ((_NM_SETTINGS_CONNECTION_INT_FLAGS_LAST - 1) << 1) - 1, } NMSettingsConnectionIntFlags; -typedef enum { - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE = 0, - - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST = (1LL << 0), - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED = (1LL << 1), - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS = (1LL << 2), - - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_ALL = - (NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST - | NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_FAILED - | NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NO_SECRETS), -} NMSettingsAutoconnectBlockedReason; - typedef struct _NMSettingsConnectionCallId NMSettingsConnectionCallId; typedef struct _NMSettingsConnectionClass NMSettingsConnectionClass; @@ -210,6 +201,7 @@ struct _NMSettingsConnectionPrivate; struct _NMSettingsConnection { NMDBusObject parent; CList _connections_lst; + CList devcon_con_lst_head; struct _NMSettingsConnectionPrivate *_priv; }; @@ -217,7 +209,13 @@ GType nm_settings_connection_get_type(void); NMSettingsConnection *nm_settings_connection_new(void); +NMSettings *nm_settings_connection_get_settings(NMSettingsConnection *self); + +NMManager *nm_settings_connection_get_manager(NMSettingsConnection *self); + NMConnection *nm_settings_connection_get_connection(NMSettingsConnection *self); +gpointer nm_settings_connection_get_setting(NMSettingsConnection *self, + NMMetaSettingType meta_type); void _nm_settings_connection_set_connection(NMSettingsConnection *self, NMConnection *new_connection, @@ -234,6 +232,9 @@ const char *nm_settings_connection_get_filename(NMSettingsConnection *self); guint64 nm_settings_connection_get_last_secret_agent_version_id(NMSettingsConnection *self); +guint64 nm_settings_connection_get_version_id(NMSettingsConnection *self); +void nm_settings_connection_bump_version_id(NMSettingsConnection *self); + gboolean nm_settings_connection_has_unmodified_applied_connection(NMSettingsConnection *self, NMConnection *applied_connection, @@ -347,31 +348,15 @@ void nm_settings_connection_add_seen_bssid(NMSettingsConnection *self, const cha guint nm_settings_connection_get_num_seen_bssids(NMSettingsConnection *self); -int nm_settings_connection_autoconnect_retries_get(NMSettingsConnection *self); -void nm_settings_connection_autoconnect_retries_set(NMSettingsConnection *self, int retries); -void nm_settings_connection_autoconnect_retries_reset(NMSettingsConnection *self); - -gint32 nm_settings_connection_autoconnect_retries_blocked_until(NMSettingsConnection *self); +gboolean nm_settings_connection_autoconnect_is_blocked(NMSettingsConnection *self); NMSettingsAutoconnectBlockedReason - nm_settings_connection_autoconnect_blocked_reason_get(NMSettingsConnection *self); -gboolean nm_settings_connection_autoconnect_blocked_reason_set_full( - NMSettingsConnection *self, - NMSettingsAutoconnectBlockedReason mask, - NMSettingsAutoconnectBlockedReason value); +nm_settings_connection_autoconnect_blocked_reason_get(NMSettingsConnection *self); -static inline gboolean +gboolean nm_settings_connection_autoconnect_blocked_reason_set(NMSettingsConnection *self, - NMSettingsAutoconnectBlockedReason mask, - gboolean set) -{ - return nm_settings_connection_autoconnect_blocked_reason_set_full( - self, - mask, - set ? mask : NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_NONE); -} - -gboolean nm_settings_connection_autoconnect_is_blocked(NMSettingsConnection *self); + NMSettingsAutoconnectBlockedReason reason, + gboolean set); const char *nm_settings_connection_get_id(NMSettingsConnection *connection); const char *nm_settings_connection_get_uuid(NMSettingsConnection *connection); diff --git a/src/core/settings/nm-settings.c b/src/core/settings/nm-settings.c index 9995b490..8796de36 100644 --- a/src/core/settings/nm-settings.c +++ b/src/core/settings/nm-settings.c @@ -222,7 +222,7 @@ _sett_conn_entry_get_conn(SettConnEntry *sett_conn_entry) * _sett_conn_entry_storage_find_conflicting_storage: * @sett_conn_entry: the list of settings-storages for the given UUID. * @target_plugin: the settings plugin to check - * @storage_check_including: (allow-none): optionally compare against this storage. + * @storage_check_including: (nullable): optionally compare against this storage. * @plugins: the list of plugins sorted in descending priority. This determines * the priority and whether a storage conflicts. * @@ -451,6 +451,16 @@ static void _startup_complete_check(NMSettings *self, gint64 now_msec); /*****************************************************************************/ +NMManager * +nm_settings_get_manager(NMSettings *self) +{ + g_return_val_if_fail(NM_IS_SETTINGS(self), NULL); + + return NM_SETTINGS_GET_PRIVATE(self)->manager; +} + +/*****************************************************************************/ + static void _emit_connection_added(NMSettings *self, NMSettingsConnection *sett_conn) { @@ -525,7 +535,7 @@ _startup_complete_check_is_ready(NMSettings *self, /* Check that device is compatible with the device. We are also happy * with a device compatible but for which the connection is disallowed * by NM configuration. */ - if (!nm_device_check_connection_compatible(device, conn, &error) + if (!nm_device_check_connection_compatible(device, conn, TRUE, &error) && !g_error_matches(error, NM_UTILS_ERROR, NM_UTILS_ERROR_CONNECTION_AVAILABLE_DISALLOWED)) @@ -1080,11 +1090,13 @@ _connection_changed_update(NMSettings *self, is_new = c_list_is_empty(&sett_conn->_connections_lst); - _LOGT("update[%s]: %s connection \"%s\" (" NM_SETTINGS_STORAGE_PRINT_FMT ")", + _LOGT("update[%s]: %s connection \"%s\" (" NM_SETTINGS_STORAGE_PRINT_FMT "), " + "new version-id %" G_GUINT64_FORMAT, nm_settings_storage_get_uuid(storage), is_new ? "adding" : "updating", nm_connection_get_id(connection), - NM_SETTINGS_STORAGE_PRINT_ARG(storage)); + NM_SETTINGS_STORAGE_PRINT_ARG(storage), + (nm_settings_connection_get_version_id(sett_conn) + 1u)); _nm_settings_connection_set_storage(sett_conn, storage); @@ -1109,7 +1121,7 @@ _connection_changed_update(NMSettings *self, if (NM_FLAGS_HAS(update_reason, NM_SETTINGS_CONNECTION_UPDATE_REASON_BLOCK_AUTOCONNECT)) { nm_settings_connection_autoconnect_blocked_reason_set( sett_conn, - NM_SETTINGS_AUTO_CONNECT_BLOCKED_REASON_USER_REQUEST, + NM_SETTINGS_AUTOCONNECT_BLOCKED_REASON_USER_REQUEST, TRUE); } @@ -1156,6 +1168,8 @@ _connection_changed_update(NMSettings *self, path); } + nm_settings_connection_bump_version_id(sett_conn); + if (is_new) { nm_dbus_object_emit_signal(NM_DBUS_OBJECT(self), &interface_info_settings, @@ -1237,6 +1251,8 @@ _connection_changed_delete(NMSettings *self, | NM_SETTINGS_CONNECTION_INT_FLAGS_EXTERNAL, FALSE); + nm_manager_notify_delete_settings_connections(priv->manager, sett_conn); + _emit_connection_removed(self, sett_conn); _nm_settings_connection_cleanup_after_remove(sett_conn); @@ -1453,10 +1469,16 @@ static void _plugin_connections_reload(NMSettings *self) { NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self); - GSList *iter; - - for (iter = priv->plugins; iter; iter = iter->next) { - nm_settings_plugin_reload_connections(iter->data, _plugin_connections_reload_cb, self); + GSList *iter_plugin; + GHashTableIter iter_entry; + SettConnEntry *entry; + gboolean warned = FALSE; + gboolean migrate; + + for (iter_plugin = priv->plugins; iter_plugin; iter_plugin = iter_plugin->next) { + nm_settings_plugin_reload_connections(iter_plugin->data, + _plugin_connections_reload_cb, + self); } _connection_changed_process_all_dirty( @@ -1469,8 +1491,53 @@ _plugin_connections_reload(NMSettings *self) | NM_SETTINGS_CONNECTION_UPDATE_REASON_RESET_AGENT_SECRETS | NM_SETTINGS_CONNECTION_UPDATE_REASON_UPDATE_NON_SECRET); - for (iter = priv->plugins; iter; iter = iter->next) - nm_settings_plugin_load_connections_done(iter->data); + for (iter_plugin = priv->plugins; iter_plugin; iter_plugin = iter_plugin->next) + nm_settings_plugin_load_connections_done(iter_plugin->data); + + migrate = nm_config_data_get_value_boolean(nm_config_get_data(priv->config), + NM_CONFIG_KEYFILE_GROUP_MAIN, + NM_CONFIG_KEYFILE_KEY_MAIN_MIGRATE_IFCFG_RH, + NM_CONFIG_DEFAULT_MAIN_MIGRATE_IFCFG_RH_BOOL); + + g_hash_table_iter_init(&iter_entry, priv->sce_idx); + while (g_hash_table_iter_next(&iter_entry, (gpointer *) &entry, NULL)) { + const char *plugin; + + plugin = nm_settings_plugin_get_plugin_name(nm_settings_storage_get_plugin(entry->storage)); + + if (nm_streq0(plugin, "ifcfg-rh")) { + if (!warned) { + if (migrate) { + nm_log_warn( + LOGD_SETTINGS, + "Warning: connections were found in ifcfg-rh format and the " + "\"main.migrate-ifcfg-rh\" option is enabled. Those connections will be " + "migrated to keyfile. To convert them back, disable the option and then " + "run \"nmcli connection migrate --plugin ifcfg-rh $UUID\""); + } else { + nm_log_info( + LOGD_SETTINGS, + "Warning: the ifcfg-rh plugin is deprecated, please migrate connections " + "to the keyfile format using \"nmcli connection migrate\""); + } + warned = TRUE; + } + if (migrate) { + _LOGW("migrating connection %s ('%s') from ifcfg-rh to keyfile", + entry->uuid, + nm_settings_connection_get_id(entry->sett_conn)); + nm_settings_connection_update(entry->sett_conn, + "keyfile", + NULL, + NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP, + NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, + NM_SETTINGS_CONNECTION_INT_FLAGS_NONE, + NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE, + "migrate-ifcfg-rh", + NULL); + } + } + } } /*****************************************************************************/ @@ -1728,7 +1795,8 @@ _set_nmmeta_tombstone(NMSettings *self, * @persist_mode: the persist-mode for this profile. * @add_reason: the add-reason flags. * @sett_flags: the settings flags to set. - * @out_sett_conn: (allow-none) (transfer none): the added settings connection on success. + * @out_sett_conn: (out) (optional) (nullable) (transfer none): the added + * settings connection on success. * @error: on return, a location to store any errors that may occur * * Creates a new #NMSettingsConnection for the given source @connection. @@ -2000,9 +2068,10 @@ nm_settings_update_connection(NMSettings *self, gs_unref_object NMConnection *new_connection_cloned = NULL; gs_unref_object NMConnection *new_connection = NULL; NMConnection *new_connection_real; - gs_unref_object NMSettingsStorage *cur_storage = NULL; - gs_unref_object NMSettingsStorage *new_storage = NULL; - NMSettingsStorage *drop_storage = NULL; + gs_unref_object NMSettingsStorage *cur_storage = NULL; + gs_unref_object NMSettingsStorage *new_storage = NULL; + NMSettingsStorage *drop_storage = NULL; + NMSettingsStorage *prev_update_storage = NULL; SettConnEntry *sett_conn_entry; gboolean cur_in_memory; gboolean new_in_memory; @@ -2246,16 +2315,17 @@ nm_settings_update_connection(NMSettings *self, drop_storage, &local); } else { - success = _update_connection_to_plugin(self, - update_storage, - connection, - new_flags, - update_reason, - new_shadowed_storage_filename, - new_shadowed_owned, - &new_storage, - &new_connection, - &local); + success = _update_connection_to_plugin( + self, + update_storage, + connection, + new_flags, + NM_FLAGS_HAS(update_reason, NM_SETTINGS_CONNECTION_UPDATE_REASON_FORCE_RENAME), + new_shadowed_storage_filename, + new_shadowed_owned, + &new_storage, + &new_connection, + &local); } if (!success) { gboolean ignore_failure; @@ -2306,6 +2376,9 @@ nm_settings_update_connection(NMSettings *self, nm_assert_not_reached(); new_connection_real = new_connection; } + + if (update_storage && new_storage != update_storage) + prev_update_storage = update_storage; } } @@ -2314,6 +2387,12 @@ nm_settings_update_connection(NMSettings *self, _connection_changed_track(self, new_storage, new_connection_real, TRUE); + if (prev_update_storage) { + /* The storage was swapped by the update call. The old one needs + * to be dropped, which we do by setting the connection to NULL. */ + _connection_changed_track(self, prev_update_storage, NULL, FALSE); + } + if (drop_storage && drop_storage != new_storage) { gs_free_error GError *local = NULL; @@ -3102,7 +3181,7 @@ error: /** * nm_settings_get_connections: * @self: the #NMSettings - * @out_len: (out) (allow-none): returns the number of returned + * @out_len: (out) (optional): returns the number of returned * connections. * * Returns: (transfer none): a list of NMSettingsConnections. The list is @@ -3205,10 +3284,10 @@ nm_settings_get_connections_sorted_by_autoconnect_priority(NMSettings *self, gui /** * nm_settings_get_connections_clone: * @self: the #NMSetting - * @out_len: (allow-none): optional output argument + * @out_len: (optional): optional output argument * @func: caller-supplied function for filtering connections * @func_data: caller-supplied data passed to @func - * @sort_compare_func: (allow-none): optional function pointer for + * @sort_compare_func: (nullable): optional function pointer for * sorting the returned list. * @sort_data: user data for @sort_compare_func. * @@ -3629,7 +3708,7 @@ have_connection_for_device(NMSettings *self, NMDevice *device) c_list_for_each_entry (sett_conn, &priv->connections_lst_head, _connections_lst) { NMConnection *connection = nm_settings_connection_get_connection(sett_conn); - if (!nm_device_check_connection_compatible(device, connection, NULL)) + if (!nm_device_check_connection_compatible(device, connection, TRUE, NULL)) continue; if (nm_settings_connection_default_wired_get_device(sett_conn)) diff --git a/src/core/settings/nm-settings.h b/src/core/settings/nm-settings.h index aba3c565..020623d0 100644 --- a/src/core/settings/nm-settings.h +++ b/src/core/settings/nm-settings.h @@ -58,6 +58,8 @@ NMSettings *nm_settings_get(void); NMSettings *nm_settings_new(NMManager *manager); +NMManager *nm_settings_get_manager(NMSettings *self); + gboolean nm_settings_start(NMSettings *self, GError **error); typedef void (*NMSettingsAddCallback)(NMSettings *settings, diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c index eb0d733d..0a385247 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-plugin.c @@ -52,7 +52,6 @@ typedef struct { GHashTable *unmanaged_specs; GHashTable *unrecognized_specs; - } NMSIfcfgRHPluginPrivate; struct _NMSIfcfgRHPlugin { @@ -177,6 +176,7 @@ nm_assert_self(NMSIfcfgRHPlugin *self, gboolean unhandled_specs_consistent) static NMSIfcfgRHStorage * _load_file(NMSIfcfgRHPlugin *self, const char *filename, GError **error) { + NMSIfcfgRHStorage *ret = NULL; gs_unref_object NMConnection *connection = NULL; gs_free_error GError *load_error = NULL; gs_free char *unhandled_spec = NULL; @@ -224,16 +224,16 @@ _load_file(NMSIfcfgRHPlugin *self, const char *filename, GError **error) nm_assert_not_reached(); return NULL; } - return nms_ifcfg_rh_storage_new_unhandled(self, + + ret = nms_ifcfg_rh_storage_new_unhandled(self, filename, unmanaged_spec, unrecognized_spec); + } else { + ret = nms_ifcfg_rh_storage_new_connection(self, filename, - unmanaged_spec, - unrecognized_spec); + g_steal_pointer(&connection), + &st.st_mtim); } - return nms_ifcfg_rh_storage_new_connection(self, - filename, - g_steal_pointer(&connection), - &st.st_mtim); + return ret; } static void diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 6cfb5705..84a9479d 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -917,7 +917,7 @@ enum { * @options_route: (in-out): when line is from the OPTIONS setting, this is a pre-created * route object that is completed with the settings from options. Otherwise, * it shall point to %NULL and a new route is created and returned. - * @out_route: (out) (transfer-full) (allow-none): the parsed %NMIPRoute instance. + * @out_route: (out) (transfer full) (optional): the parsed %NMIPRoute instance. * In case a @options_route is passed in, it returns the input route that was modified * in-place. But the caller must unref the returned route in either case. * @error: the failure description. @@ -2481,6 +2481,11 @@ make_ip6_setting(shvarFile *ifcfg, shvarFile *network_ifcfg, gboolean routes_rea g_object_set(s_ip6, NM_SETTING_IP_CONFIG_DHCP_IAID, v, NULL); nm_clear_g_free(&value); + v = svGetValueStr(ifcfg, "DHCPV6_PD_HINT", &value); + if (v) + g_object_set(s_ip6, NM_SETTING_IP6_CONFIG_DHCP_PD_HINT, v, NULL); + + nm_clear_g_free(&value); v = svGetValueStr(ifcfg, "DHCPV6_HOSTNAME", &value); /* Use DHCP_HOSTNAME as fallback if it is in FQDN format and ipv6.method is * auto or dhcp: this is required to support old ifcfg files @@ -2591,7 +2596,7 @@ make_ip6_setting(shvarFile *ifcfg, shvarFile *network_ifcfg, gboolean routes_rea &local)) { PARSE_WARNING("%s", local->message); g_clear_error(&local); - } else if (errno == ENOENT) { + } else if (errno == ENOKEY) { /* The key is not specified. If "v" (IPV6_TOKEN) is set, * we default to EUI64. Otherwise, the connection would not verify. */ if (v) @@ -2683,16 +2688,25 @@ make_hostname_setting(shvarFile *ifcfg) NMTernary from_dns_lookup; NMTernary only_from_default; int priority; + gboolean has_setting = FALSE; priority = svGetValueInt64(ifcfg, "HOSTNAME_PRIORITY", 10, G_MININT32, G_MAXINT32, 0); + if (!has_setting && errno != ENOKEY) + has_setting = TRUE; + + from_dhcp = svGetValueTernary(ifcfg, "HOSTNAME_FROM_DHCP"); + if (!has_setting && errno != ENOKEY) + has_setting = TRUE; + + from_dns_lookup = svGetValueTernary(ifcfg, "HOSTNAME_FROM_DNS_LOOKUP"); + if (!has_setting && errno != ENOKEY) + has_setting = TRUE; - from_dhcp = svGetValueTernary(ifcfg, "HOSTNAME_FROM_DHCP"); - from_dns_lookup = svGetValueTernary(ifcfg, "HOSTNAME_FROM_DNS_LOOKUP"); only_from_default = svGetValueTernary(ifcfg, "HOSTNAME_ONLY_FROM_DEFAULT"); + if (!has_setting && errno != ENOKEY) + has_setting = TRUE; - /* Create the setting when at least one key is not default*/ - if (priority == 0 && from_dhcp == NM_TERNARY_DEFAULT && from_dns_lookup == NM_TERNARY_DEFAULT - && only_from_default == NM_TERNARY_DEFAULT) + if (!has_setting) return NULL; setting = nm_setting_hostname_new(); diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c index 207b8700..50e352d3 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.c @@ -881,6 +881,7 @@ const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[] = { _KEY_TYPE("DHCPV6_HOSTNAME", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("DHCPV6_HOSTNAME_FLAGS", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("DHCPV6_IAID", NMS_IFCFG_KEY_TYPE_IS_PLAIN), + _KEY_TYPE("DHCPV6_PD_HINT", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("DHCPV6_SEND_HOSTNAME", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("DHCP_CLIENT_ID", NMS_IFCFG_KEY_TYPE_IS_PLAIN), _KEY_TYPE("DHCP_FQDN", NMS_IFCFG_KEY_TYPE_IS_PLAIN), diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h index 51b118e3..eb9e418a 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-utils.h @@ -33,7 +33,7 @@ typedef struct { NMSIfcfgKeyTypeFlags key_flags; } NMSIfcfgKeyTypeInfo; -extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[263]; +extern const NMSIfcfgKeyTypeInfo nms_ifcfg_well_known_keys[264]; const NMSIfcfgKeyTypeInfo *nms_ifcfg_well_known_key_find_info(const char *key, gssize *out_idx); diff --git a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 97637063..08deaf5a 100644 --- a/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/core/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -62,6 +62,24 @@ /*****************************************************************************/ static void +set_error_unsupported(GError **error, + NMConnection *connection, + const char *name, + gboolean is_setting) +{ + g_set_error(error, + NM_SETTINGS_ERROR, + NM_SETTINGS_ERROR_NOT_SUPPORTED_BY_PLUGIN, + "The ifcfg-rh plugin doesn't support %s '%s'. If you are modifying an existing " + "connection profile saved in ifcfg-rh format, please migrate the connection to " + "keyfile using 'nmcli connection migrate %s' or via the Update2() D-Bus API " + "and try again.", + is_setting ? "setting" : "property", + name, + nm_connection_get_uuid(connection)); +}; + +static void save_secret_flags(shvarFile *ifcfg, const char *key, NMSettingSecretFlags flags) { GString *str; @@ -3100,6 +3118,9 @@ write_ip6_setting(NMConnection *connection, shvarFile *ifcfg, GString **out_rout "DHCPV6_DUID", nm_setting_ip6_config_get_dhcp_duid(NM_SETTING_IP6_CONFIG(s_ip6))); svSetValueStr(ifcfg, "DHCPV6_IAID", nm_setting_ip_config_get_dhcp_iaid(s_ip6)); + svSetValueStr(ifcfg, + "DHCPV6_PD_HINT", + nm_setting_ip6_config_get_dhcp_pd_hint(NM_SETTING_IP6_CONFIG(s_ip6))); hostname = nm_setting_ip_config_get_dhcp_hostname(s_ip6); svSetValueStr(ifcfg, "DHCPV6_HOSTNAME", hostname); @@ -3485,6 +3506,11 @@ do_write_construct(NMConnection *connection, write_sriov_setting(connection, ifcfg); write_tc_setting(connection, ifcfg); + if (_nm_connection_get_setting(connection, NM_TYPE_SETTING_LINK)) { + set_error_unsupported(error, connection, "link", TRUE); + return FALSE; + } + route_path_is_svformat = utils_has_route_file_new_syntax(route_path); has_complex_routes_v4 = utils_has_complex_routes(ifcfg_name, AF_INET); diff --git a/src/core/settings/plugins/ifcfg-rh/shvar.c b/src/core/settings/plugins/ifcfg-rh/shvar.c index fe8187c3..1ca2ea60 100644 --- a/src/core/settings/plugins/ifcfg-rh/shvar.c +++ b/src/core/settings/plugins/ifcfg-rh/shvar.c @@ -97,23 +97,32 @@ static void _line_link_parse(shvarFile *s, const char *value, gsize len); * in case no valid value is found, the fallback value. Valid values * are: "yes", "true", "t", "y", "1" and "no", "false", "f", "n", "0". * + * Always sets errno. Either to zero on success, to ENOKEY for NULL + * or to EINVAL otherwise. + * * Returns: the parsed boolean value or @fallback. */ int svParseBoolean(const char *value, int fallback) { - if (!value) + if (!value) { + errno = ENOKEY; return fallback; + } if (!g_ascii_strcasecmp("yes", value) || !g_ascii_strcasecmp("true", value) || !g_ascii_strcasecmp("t", value) || !g_ascii_strcasecmp("y", value) - || !g_ascii_strcasecmp("1", value)) + || !g_ascii_strcasecmp("1", value)) { + errno = 0; return TRUE; - else if (!g_ascii_strcasecmp("no", value) || !g_ascii_strcasecmp("false", value) - || !g_ascii_strcasecmp("f", value) || !g_ascii_strcasecmp("n", value) - || !g_ascii_strcasecmp("0", value)) + } else if (!g_ascii_strcasecmp("no", value) || !g_ascii_strcasecmp("false", value) + || !g_ascii_strcasecmp("f", value) || !g_ascii_strcasecmp("n", value) + || !g_ascii_strcasecmp("0", value)) { + errno = 0; return FALSE; + } + errno = EINVAL; return fallback; } @@ -1253,6 +1262,7 @@ svGetValueStr_cp(shvarFile *s, const char *key) * @fallback: the fallback value in any error case * * Reads a value @key and converts it to a boolean using svParseBoolean(). + * This always sets errno, see svParseBoolean(). * * Returns: the parsed boolean value or @fallback. */ @@ -1271,6 +1281,7 @@ svGetValueBoolean(shvarFile *s, const char *key, int fallback) * @key: the name of the key to read * * Reads a value @key and converts it to a NMTernary value. + * This always sets errno, see svParseBoolean(). * * Returns: the parsed NMTernary */ @@ -1328,7 +1339,7 @@ svGetValueEnum(shvarFile *s, const char *key, GType gtype, int *out_value, GErro if (!svalue) { /* don't touch out_value. The caller is supposed * to initialize it with the default value. */ - errno = ENOENT; + errno = ENOKEY; return TRUE; } diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c b/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c index 1d7de8d2..1679cab6 100644 --- a/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c +++ b/src/core/settings/plugins/keyfile/nms-keyfile-plugin.c @@ -891,6 +891,7 @@ nms_keyfile_plugin_update_connection(NMSKeyfilePlugin *self, gboolean reread_same; const char *uuid; char strbuf[100]; + NMTernary force_rename2; _nm_assert_storage(self, storage, TRUE); nm_assert(NM_IS_CONNECTION(connection)); @@ -910,6 +911,20 @@ nms_keyfile_plugin_update_connection(NMSKeyfilePlugin *self, previous_filename = nms_keyfile_storage_get_filename(storage); uuid = nms_keyfile_storage_get_uuid(storage); + if (force_rename) + force_rename2 = NM_TERNARY_TRUE; + else { + /* If the caller does not force a rename, we honor [keyfile].rename + * setting, and (if enabled) we rename by following the preferred name + * as necessary. That's indicated with NM_TERNARY_DEFAULT. */ + force_rename2 = nm_config_data_get_value_boolean(NM_CONFIG_GET_DATA, + NM_CONFIG_KEYFILE_GROUP_KEYFILE, + NM_CONFIG_KEYFILE_KEY_KEYFILE_RENAME, + FALSE) + ? NM_TERNARY_DEFAULT + : NM_TERNARY_FALSE; + } + if (!nms_keyfile_writer_connection( connection, is_nm_generated, @@ -922,7 +937,7 @@ nms_keyfile_plugin_update_connection(NMSKeyfilePlugin *self, _get_plugin_dir(priv), previous_filename, FALSE, - FALSE, + force_rename2, nm_sett_util_allow_filename_cb, NM_SETT_UTIL_ALLOW_FILENAME_DATA(&priv->storages, previous_filename), &full_filename, @@ -938,7 +953,8 @@ nms_keyfile_plugin_update_connection(NMSKeyfilePlugin *self, return FALSE; } - nm_assert(full_filename && nm_streq(full_filename, previous_filename)); + nm_assert(full_filename); + nm_assert(force_rename2 != NM_TERNARY_FALSE || nm_streq(full_filename, previous_filename)); if (!reread || reread_same) nm_g_object_ref_set(&reread, connection); @@ -957,11 +973,33 @@ nms_keyfile_plugin_update_connection(NMSKeyfilePlugin *self, "\")", "")); - storage->u.conn_data.is_nm_generated = is_nm_generated; - storage->u.conn_data.is_volatile = is_volatile; - storage->u.conn_data.is_external = is_external; - storage->u.conn_data.stat_mtime = *nm_sett_util_stat_mtime(full_filename, FALSE, &mtime); - storage->u.conn_data.shadowed_owned = shadowed_owned; + nm_sett_util_stat_mtime(full_filename, FALSE, &mtime); + + if (nm_streq(full_filename, previous_filename)) { + storage->u.conn_data.is_nm_generated = is_nm_generated; + storage->u.conn_data.is_volatile = is_volatile; + storage->u.conn_data.is_external = is_external; + storage->u.conn_data.stat_mtime = mtime; + storage->u.conn_data.shadowed_owned = shadowed_owned; + } else { + NMSKeyfileStorage *storage_new; + + /* The filename changed. We cannot modify the filename of an NMSettingsStorage. + * We need to create a new one. */ + storage_new = + nms_keyfile_storage_new_connection(NMS_KEYFILE_PLUGIN(storage->parent._plugin), + g_object_ref(reread), + full_filename, + storage->storage_type, + is_nm_generated, + is_volatile, + is_external, + storage->u.conn_data.shadowed_storage, + shadowed_owned, + &mtime); + nm_sett_util_storages_add_take(&priv->storages, storage_new); + storage = storage_new; + } *out_storage = g_object_ref(NM_SETTINGS_STORAGE(storage)); *out_connection = g_steal_pointer(&reread); @@ -1066,12 +1104,12 @@ delete_connection(NMSettingsPlugin *plugin, NMSettingsStorage *storage_x, GError * @shadowed_storage: a tombstone can also shadow an existing storage. * In combination with @set and @in_memory, this is allowed to store * the shadowed storage filename. - * @out_storage: (transfer full) (allow-none): the storage element that changes, or - * NULL if nothing changed. Note that the file on disk is already as - * we want to write it, then this still counts as a change. No change only + * @out_storage: (transfer full) (optional) (nullable): the storage element that + * changes, or %NULL if nothing changed. Note that the file on disk is already + * as we want to write it, then this still counts as a change. No change only * means if we try to delete a storage (@set %FALSE) that did not * exist previously. - * @out_hard_failure: (allow-none): on failure, indicate that this is a hard failure. + * @out_hard_failure: (optional): on failure, indicate that this is a hard failure. * * The function writes or deletes nmmeta files to/from filesystem. In this case, * the nmmeta files can only be symlinks to /dev/null (to indicate tombstones). diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-writer.c b/src/core/settings/plugins/keyfile/nms-keyfile-writer.c index ad6f277c..b1dd2e44 100644 --- a/src/core/settings/plugins/keyfile/nms-keyfile-writer.c +++ b/src/core/settings/plugins/keyfile/nms-keyfile-writer.c @@ -195,7 +195,7 @@ _internal_write_connection(NMConnection *connection, pid_t owner_grp, const char *existing_path, gboolean existing_path_read_only, - gboolean force_rename, + NMTernary force_rename, NMSKeyfileWriterAllowFilenameCb allow_filename_cb, gpointer allow_filename_user_data, char **out_path, @@ -212,6 +212,7 @@ _internal_write_connection(NMConnection *connection, gs_free_error GError *local_err = NULL; int errsv; gboolean rename; + gboolean rename_follow; int i_path; gs_unref_object NMConnection *reread = NULL; gboolean reread_same = FALSE; @@ -223,8 +224,12 @@ _internal_write_connection(NMConnection *connection, nm_assert(!shadowed_owned || shadowed_storage); - rename = force_rename || existing_path_read_only - || (existing_path && !nm_utils_file_is_in_path(existing_path, keyfile_dir)); + rename = existing_path_read_only + || (existing_path && !nm_utils_file_is_in_path(existing_path, keyfile_dir)) + || force_rename == NM_TERNARY_TRUE; + + /* Follow the connection.id upon change. */ + rename_follow = !rename && existing_path && force_rename == NM_TERNARY_DEFAULT; id = nm_connection_get_id(connection); nm_assert(id && *id); @@ -283,7 +288,7 @@ _internal_write_connection(NMConnection *connection, gboolean is_existing_path; if (i_path == -2) { - if (!existing_path || rename) + if (!existing_path || rename || rename_follow) continue; path_candidate = g_strdup(existing_path); } else if (i_path == -1) { @@ -427,7 +432,7 @@ nms_keyfile_writer_connection(NMConnection *connection, const char *profile_dir, const char *existing_path, gboolean existing_path_read_only, - gboolean force_rename, + NMTernary force_rename, NMSKeyfileWriterAllowFilenameCb allow_filename_cb, gpointer allow_filename_user_data, char **out_path, @@ -458,14 +463,14 @@ nms_keyfile_writer_connection(NMConnection *connection, } gboolean -nms_keyfile_writer_test_connection(NMConnection *connection, - const char *keyfile_dir, - uid_t owner_uid, - pid_t owner_grp, - char **out_path, - NMConnection **out_reread, - gboolean *out_reread_same, - GError **error) +nmtst_keyfile_writer_test_connection(NMConnection *connection, + const char *keyfile_dir, + uid_t owner_uid, + pid_t owner_grp, + char **out_path, + NMConnection **out_reread, + gboolean *out_reread_same, + GError **error) { return _internal_write_connection(connection, FALSE, diff --git a/src/core/settings/plugins/keyfile/nms-keyfile-writer.h b/src/core/settings/plugins/keyfile/nms-keyfile-writer.h index 62aaa19d..850d5522 100644 --- a/src/core/settings/plugins/keyfile/nms-keyfile-writer.h +++ b/src/core/settings/plugins/keyfile/nms-keyfile-writer.h @@ -22,7 +22,7 @@ gboolean nms_keyfile_writer_connection(NMConnection *connectio const char *profile_dir, const char *existing_path, gboolean existing_path_read_only, - gboolean force_rename, + NMTernary force_rename, NMSKeyfileWriterAllowFilenameCb allow_filename_cb, gpointer allow_filename_user_data, char **out_path, @@ -30,13 +30,13 @@ gboolean nms_keyfile_writer_connection(NMConnection *connectio gboolean *out_reread_same, GError **error); -gboolean nms_keyfile_writer_test_connection(NMConnection *connection, - const char *keyfile_dir, - uid_t owner_uid, - pid_t owner_grp, - char **out_path, - NMConnection **out_reread, - gboolean *out_reread_same, - GError **error); +gboolean nmtst_keyfile_writer_test_connection(NMConnection *connection, + const char *keyfile_dir, + uid_t owner_uid, + pid_t owner_grp, + char **out_path, + NMConnection **out_reread, + gboolean *out_reread_same, + GError **error); #endif /* __NMS_KEYFILE_WRITER_H__ */ diff --git a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c index 83019bab..866b1ffd 100644 --- a/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c +++ b/src/core/settings/plugins/keyfile/tests/test-keyfile-settings.c @@ -138,14 +138,14 @@ write_test_connection_reread(NMConnection *connection, connection_normalized = nmtst_connection_duplicate_and_normalize(connection); - success = nms_keyfile_writer_test_connection(connection_normalized, - TEST_SCRATCH_DIR, - owner_uid, - owner_grp, - testfile, - out_reread, - out_reread_same, - p_error); + success = nmtst_keyfile_writer_test_connection(connection_normalized, + TEST_SCRATCH_DIR, + owner_uid, + owner_grp, + testfile, + out_reread, + out_reread_same, + p_error); g_assert_no_error(error); g_assert(success); g_assert(*testfile && (*testfile)[0]); |