There are two callers that are concerned with disconnecting/releasing a
setting:
- _setting_release_hfr() (formerly _setting_release())
- _nm_connection_add_setting() for the @s_old setting
Compared to one caller that connects/adds a setting (_nm_connection_add_setting()).
Refactor the two callers to use the same helper function
(_setting_release()) so that the implementation of how to release a
setting is at one place.
This patch was originally done when adding another signal to NMSetting.
That did not happen (yet), but the refactoring still makes sense.
And merge it with the version that uses no flags.
Previously, clear_secrets(_with_flags()) was only implemented
by NMSettingVpn. All other settings would only consider GObject-based
properties.
As we will add secrets that have no GObject property, call the virtual
function always, so that the setting can hook into this (for WireGuard
peers).
The secret name should be the one that we can pass to nm_setting_get_secret_flags().
It's wrong to call the function repeatedly with secret-name "secrets".
Probably nobody cared anyway about the name. nm_connection_clear_secrets_with_func()
is used to clear secrets based on the flags, not the secret-name.
Fixes: 2b2404bbef
Add a hook so that we can overwrite the property info.
Yes, this is an API/ABI change for NMSettingClass, which is in a
header file. But this is not API that we want to support. Users must
not use this. Alternatively, I could hook the callback into
NMSettInfoSetting, but either works.
Order the code in our common way. No other changes.
- ensure to include the main header first (directly after
"nm-default.h").
- reorder function definitions: get_property(), set_property(),
*_init(), *_new(), finalize(), *_class_init().
_log_connection_get_property() is a hack, as it cannot meaningfully print complex
properties. Also, it uses _nm_setting_get_property() which can only work with GObject
base properties.
Don't assert against _nm_setting_get_property() returning success. Eventually
we should replace _nm_setting_get_property() by something better. But for the moment,
it's fine to being unable to print a property value.
Curreently all aggregate types only care about secrets.
The check for secets is done by checking for NM_SETTING_PARAM_SECRET
flag. Assert that this check is suitable to identify a secret.
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
nm_setting_compare() and nm_setting_diff() both call the virtual
function compare_property(). But their check for determining whether
to call the virtual function differs.
In a first step, merge the implementations so that the check is clearly
similar in both cases.
The flags NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS and
NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS act on the secret flags
to decide whether to ignore a secret.
But there was not test how this behaved, if the two settings had
differing flags.
ethernet.cloned-mac-address is also marked as inferrable. I think the concept
of NM_SETTING_PARAM_INFERRABLE is fundamentally wrong just like the entire
assume approach. Anyway, if ethernet's property is inferrable, so should
be Wi-Fi's.
This bug had no effect, because NM_SETTING_COMPARE_FLAG_IGNORE_REAPPLY_IMMEDIATELY
has only one user, and it's used there in combination with
nm_setting_compare(). No caller passed this flag to nm_setting_diff().
Fixes: c9b3617c35
We have bridge min/max/default values in core-internal. Do the same
for bridge port ones.
We will soon use those values to enforce limits when assuming a
bridge port configuration.
In NetworkManager we have a default port path-cost equal to 100.
In the linux kernel the default port cost depends upon the interface
speed: 2 for 10Gb, 4 for 1Gb, 19 for 100Mb and 100 for 10Mb (or when the
interface speed is not available, like current virtio_net driver).
Allow NetworkManager to assume bridge port connections also when the
path-cost differs: this will allow us to assume bridge ports created
outside NetworkManager (e.g. in initrd) that will likely have a different
"cost" value.
This is a flags type, not an enum.
This affects the generated glib-mkenums type, changing it from GEnum to
GFlags. That is possibly a change in behavior for language bindings, but
hopefully nobody is badly affected by this.
Fixes: e6f95b50c8
Secret-flags are flags, but most combinations don't actually make sense
and maybe should be rejected. Anyway, that is not done, and most places
just check that there are no unknown flags set.
Add _nm_setting_secret_flags_valid() to perform the check at one place
instead of having the implementation at various places.
- nm_setting_enumerate_values() cannot handle non-GObject based
properties as it cannot abstract them. That means, for gendata
based settings, we need already a special case, and future ways
of handling settings (WireGuard peers) also won't work without
special casing.
- nm_setting_enumerate_values() needs to fetch all properties, although
some properties will not be actually used. E.g. secret properties will
be ignored depending on the flag.
Or compare the read-side with read_one_setting_value(). The reader doesn't
care about the (unset) GObject property. It really just cares about the
GType of the proeprty. Still, nm_setting_enumerate_values() fetches all
(empty) properties.
Or consider, route_writer() as called by nm_setting_enumerate_values()
always needs to deep-clone the entire list of routes in the property
getter for NM_SETTING_IP_CONFIG_ROUTES, then unpack it. This is
unnecesary overhead. This is not yet fixed, but would now be easy to
improve.
- a for-each function like nm_setting_enumerate_values() does make code
harder to read, gives less possibility for optimization, and is in
general less flexible. Don't use it.
Drop another use of nm_setting_enumerate_values().
Using nm_setting_enumerate_values() to duplicate a setting already
didn't work for gendata based settings.
Also, nm_setting_enumerate_values() would iterate the properties
in a particular order. We don't need that, the default order
(asciibetical sorted) is fine.
The property infos are already sorted by name. As nm_setting_enumerate_values()
now uses that information, in most cases there is nothing to sort.
The only instance is NMSettingConnection, which has a different
sort-order. At least for some purposes, not all:
- nm_setting_enumerate_values(), obviously.
- nm_setting_enumerate_values() is called by keyfile writer. That
means, keyfile writer will persist properties in a sorted way.
Cache the property list with alternative sorting also in the
setting-meta data, instead of calculating it each time.
Beside caching the information, this has the additional benefit that
this kind of sorting is now directly available, without calling
nm_setting_enumerate_values(). Meaning, we can implement keyfile writer
without using nm_setting_enumerate_values().
We should no longer use nm_connection_for_each_setting_value() and
nm_setting_for_each_value(). It's fundamentally broken as it does
not work with properties that are not backed by a GObject property
and it cannot be fixed because it is public API.
Add an internal function _nm_connection_aggregate() to replace it.
Compare the implementation of the aggregation functionality inside
libnm with the previous two checks for secret-flags that it replaces:
- previous approach broke abstraction and require detailed knowledge of
secret flags. Meaning, they must special case NMSettingVpn and
GObject-property based secrets.
If we implement a new way for implementing secrets (like we will need
for WireGuard), then this the new way should only affect libnm-core,
not require changes elsewhere.
- it's very inefficient to itereate over all settings. It involves
cloning and sorting the list of settings, and retrieve and clone all
GObject properties. Only to look at secret properties alone.
_nm_connection_aggregate() is supposed to be more flexible then just
the two new aggregate types that perform a "find-any" search. The
@arg argument and boolean return value can suffice to implement
different aggregation types in the future.
Also fixes the check of NMAgentManager for secret flags for VPNs
(NM_CONNECTION_AGGREGATE_ANY_SYSTEM_SECRET_FLAGS). A secret for VPNs
is a property that either has a secret or a secret-flag. The previous
implementation would only look at present secrets and
check their flags. It wouldn't check secret-flags that are
NM_SETTING_SECRET_FLAG_NONE, but have no secret.
There are 3 kinds of secret flag implementations:
1) regular properties have a GObject property and a corresponding
"-flags" property.
2) NMSettingVpn handles this entirely differently
3) NMSettingWirelessSecurity's WEP keys, where the secret keys
share a flags property that does not follow the same naming
scheme as 1).
The getter and setter had a boolean "verifiy_secret", only to
handle 3). Drop that parameter. Don't let NMSettingWirelessSecurity
call the parent's implementation for WEP keys. Just let it handle
it directly.
- most of the time, the secret-name is short and fits in a
stack-allocated buffer.
Optimize for that by using nm_construct_name_a().
- use _nm_utils_ascii_str_to_int64() instead of strtoul().
tmp = strtoul ((const char *) val, NULL, 10);
if ((errno != 0) || (tmp > NM_SETTING_SECRET_FLAGS_ALL)) {
is not the right way to check for errors of strtoul().
- refactor the code to return-early on errors.
- since commit 9b96bfaa72 "setting-vpn: whatever is in vpn.secrets always
is a secrets", we accept secrets without secret-flags as valid too.
However, only do that, when we at least have a corresponding key in
priv->secrets hash. If the secret name is not used at all, it's
clearly not a secret.
- if the secret flags are not a valid number, pretend that the flags
are still set to "none" (zero). That is because we use the presence
of the "*-flags" data item as indication that this is in fact a
secret. The user cannot use data items with such a name for another
purpose, so on failure, we still claim that this is in fact a secret.
We have a concept of setting and property meta-data that extends plain
GObject properties. While most properties are indeed backed by an
implemented as a GObject property, some are not.
Reuse the object property meta-data instead of fetching the list of
properties. Note that there is not much change in behavior, because
at all places where this is done, properties which are not backed by a
GObject property are skipped for the moment.
If nothing else, we save needlessly cloning the property list.
Later possibly we may no longer want to do that and add virtual
functions that can handle all properties.
- previously, writer would use nm_keyfile_plugin_kf_set_integer() for
G_TYPE_UINT types.
That means, values larger than G_MAXINT would be stored as negative
values. On the other hand, the reader would always reject negative
values.
Fix that, by parsing the integer ourself.
Note that we still reject the old (negative) values and there is no
compatibility for accepting such values. They were not accepted by
reader in the past and so they are still rejected.
This affects for example ethernet.mtu setting (arguably, the MTU
is usually set to small values where the issue was not apparent).
This is also covered by a test.
- no longer use nm_keyfile_plugin_kf_set_integer().
nm_keyfile_plugin_kf_set_integer() calls g_key_file_get_integer(), which
uses g_key_file_parse_integer_as_value(). That one has the odd
behavior of accepting "<number><whitespace><bogus>" as valid. Note how that
differs from g_key_file_parse_value_as_double() which rejects trailing data.
Implement the parsing ourself. There are some changes here:
- g_key_file_parse_value_as_integer() uses strtol() with base 10.
We no longer require a certain the base, so '0x' hex values are allowed
now as well.
- bogus suffixes are now rejected but were accepted by g_key_file_parse_value_as_integer().
We however still accept leading and trailing whitespace, as before.
- use nm_g_object_set_property*(). g_object_set() asserts that the value
is in range. We cannot pass invalid values without checking that they
are valid.
- emit warnings when values cannot be parsed. Previously they would
have been silently ignored or fail an assertion during g_object_set().
- don't use "helpers" like nm_keyfile_plugin_kf_set_uint64(). These
merely call GKeyFile's setters (taking care of aliases). The setters
of GKeyFile don't do anything miraculously, they merely call
g_key_file_set_value() with the string that one would expect.
Convert the numbers/boolean ourselfs. For one, we don't require
a heap allocation to convert a number to string. Also, there is
no point in leaving this GKeyFile API, because even if GKeyFile
day would change, we still must continue to support the present
format, as that is what users have on disk. So, even if a new
way would be implemented by GKeyFile, the current way must forever
be accepted too. Hence, we don't need this abstraction.
We will need access to the serialization flags from within the synth_func().
That will be for WireGuard's peers. Peers are a list of complex, structured
elements, and some fields (the peer's preshared-key) are secret and
others are not. So when serializing the peers, we need to know whether
to include secrets or not.
Instead of letting _nm_setting_to_dbus() check the flags, pass them
down.
While at it, don't pass the property_name argument. Instead, pass the
entire meta-data information we have. Most synth functions don't care
about the property or the name either way. But we should not pre-filter
information that we have at hand. Just pass it to the synth function.
If the synth function would be public API, that would be a reason to be
careful about what we pass. But it isn't and it only has one caller.
So passing it along is fine. Also, do it now when adding the flags
argument, as we touch all synth implementations anyway.
We shall not shortcut the synth function. If the synth function is
unhappy about a missing NMConnection argument, then that needs to be
fixed.
So, revert 395c385b9 and fix the issue in nm_setting_wireless_get_security()
differently. I presume that is the only place that caused problems,
since the history of the patch does not clealy show what the problem
was.
This reverts commit 395c385b9b.
It's not yet used, but it will be. We will need nm_sd_utils_unbase64mem()
to strictly validate WireGuard settings, which contain keys in base64 encoding.
Note that we also need a stub implementation for logging. This will do
nothing for all logging from "libnm-systemd-shared.a". This makes
sense because "libnm.so" as a library should not log directly. Also,
"libnm.so" will only use a small portion of "libnm-systemd-shared.a" which
doesn't log anything. Thus this code is unused and dropped by the linker
with "--gc-sections".
- in nm_keyfile_read(), unify _read_setting() and
_read_setting_vpn_secret() in they way they are called
(that is, they no longer return any value and don't accept
any arguments aside @info).
- use cleanup attributes
- use nm_streq() instead of strcmp().
- wrap lines that have multiple statements or conditions.
Several callers access the length output argument, expecting
it to be zero also on failure. That is a bug, because glib does
not guarantee that.
Fix that by making a stronger promise from our wrappers: the output
argument should also be set on failure.
Also ensure that calls to g_keyfile_get_groups() and
g_keyfile_get_keys() don't rely on the length output to be valid,
when the function call fails.
Actually, these issues were not severe because:
- `g_key_file_get_*_list()`'s implementation always sets the output length
even on failure (undocumented).
- `g_key_file_get_groups()` cannot fail and always set the length.
- `g_key_file_get_keys()` is called under circumstances where it won't
fail.
Still, be explicit about it.