Supplicant does not allow setting certain properties to empty values.
It also does not make sense.
Also, ifcfg-rh writer uses svSetValueStr() for these properties, so
the ifcfg plugin would always loose having hte values set to "".
Also, you couldn't enter these strings in nmcli.
It's fair to assume that it makes no sense to have these values set to
an empty value. Since we cannot just tighten up verification to reject
them, normalize them.
It also seems that some GUI now starts setting domain_suffix_match to an
empty string. Or maybe it was always doing it, and ifcfg plugin just hid
the problem? Anyway, we have users out there who set these properties to
"".
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/973
It has no actual dependency on the crypto library. All it does, is
to be careful about not leaking secrets in memory. We have code
for that in libnm-glib-aux already. Move.
The goal is to reduce the number of places where we use libnm-crypto,
because that has a large dependency. libnm-glib-aux is a very light
dependency instead.
libnm-core is also used by the daemon, thus currently dragging in
libnm-crypto there. But could we ever drop that dependency?
One use of the libnm-crypto is in functions like nm_utils_file_is_certificate()
in "nm-utils.h". These are part of the public API of libnm.
But this is not used by the daemon. Move it to "libnm-client-core"
to be closer to where it's actually used.
As we have unit tests in "libnm-core-impl/tests" that test this function,
those unit tests also would need to move to "libnm-client-impl".
Instead, add the actual implementation of these function to "libnm-crypto"
and test it there.
This patch moves forward declarations from public header "nm-utils.h" to
"nm-client.h". Arguably, "nm-client.h" is not a great name, but we don't
have a general purpose header in "libnm-client-public", so use this.
Note that libnm users can only include <NetworkManager.h> and including
individual files is not supported (and even prevented). Thus moving
the declarations won't break any users.
libnm-core currently has a dependency on crypto libraries (either
"gnutls", "nss" or "null"). We need this huge dependency for few cases.
Move the crypto code to a separate static library"src/libnm-crypto/libnm-crypto.la".
The reasoning is that it becomes clearer where we have this dependency,
to use it more consciously, and to be better see how it's used.
We clearly need the crypto functionality in libnm. But do we also need
it in the daemon? Could we ever link the daemon without crypto libraries?
The goal of splitting the crypto part out, to better understand the
crypto dependency.
"nm-error.h" is public API of libnm, and contains error numbers and
quarks. Clearly our "nm-crypto" implementation wants to use those
errors.
I want to move "nm-crypto" out of libnm, and as it's more basic, I think
it should not have a dependency on all of libnm-core. Also because
libnm-core currently uses nm-crypto, so there would be a circular
dependency. Which would be possible to do (libnm-core-aux-intern is
also used in such a way). But it's better avoided, to have clear
hierarchy of dependencies.
Add a version of the same error codes to libnm-base. libnm-base is a
very basic dependency (just one step above libnm-glib-aux).
nm_utils_bin2hexstr() is part of public libnm API.
That means, if we want to use this function, we need to link with
libnm-core-impl.
This is used by "nm-crypto.c". That file is currently part of
libnm-core, but that will change.
Move the implementation to libnm-glib-aux, so that we can use this code
from all our glib-based code (because all our glib-based code is allowed
to link with libnm-glib-aux).
When a static function only has one caller, it is often simpler to not
have the code in a separate function. Drop need_private_key_password()
and move it to need_secrets_tls().
g_warning() for unexpected scheme is not right. Either, this should be an
assertion (and never be hit), or the library should be silent about conditions
that can happen regularly.
I think code is easier to understand, if the difference (between phase1
and phase2) is pushed to the bottom. Having one large "if(phase2){}else{}"
at the top makes it harder to compare the two branches and see where
they differ.
Previously, only the daemon was writing keyfiles, and it ensures
that they are always valid.
As we now have this function as public API of libnm, we should drop this
restriction and write the profile the best we can. Granted, an invalid
profile may not be expressed in keyfile format, and the result is
undefined. But make the best of it.
This is severe. We cache the list of names, and we must invalidate the
cache when the names change. Otherwise, out-of-bound access and crash.
Fixes: d0192b698e ('libnm: add nm_setting_option_set(), nm_setting_option_get_boolean(), nm_setting_option_set_boolean()')
Fixes: 150af44e10 ('libnm: add nm_setting_option_get_uint32(), nm_setting_option_set_uint32()')
gcc-12.0.1-0.8.fc36 is annoying with false positives.
It's related to g_error() and its `for(;;) ;`.
For example:
../src/libnm-glib-aux/nm-shared-utils.c: In function 'nm_utils_parse_inaddr_bin_full':
../src/libnm-glib-aux/nm-shared-utils.c:1145:26: error: dangling pointer to 'error' may be used [-Werror=dangling-pointer=]
1145 | error->message);
| ^~
/usr/include/glib-2.0/glib/gmessages.h:343:32: note: in definition of macro 'g_error'
343 | __VA_ARGS__); \
| ^~~~~~~~~~~
../src/libnm-glib-aux/nm-shared-utils.c:1133:31: note: 'error' declared here
1133 | gs_free_error GError *error = NULL;
| ^~~~~
/usr/include/glib-2.0/glib/gmessages.h:341:25: error: dangling pointer to 'addrbin' may be used [-Werror=dangling-pointer=]
341 | g_log (G_LOG_DOMAIN, \
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
342 | G_LOG_LEVEL_ERROR, \
| ~~~~~~~~~~~~~~~~~~~~~~~
343 | __VA_ARGS__); \
| ~~~~~~~~~~~~
../src/libnm-glib-aux/nm-shared-utils.c:1141:13: note: in expansion of macro 'g_error'
1141 | g_error("unexpected assertion failure: could parse \"%s\" as %s, but not accepted by "
| ^~~~~~~
../src/libnm-glib-aux/nm-shared-utils.c:1112:14: note: 'addrbin' declared here
1112 | NMIPAddr addrbin;
| ^~~~~~~
I think the warning could potentially be useful and prevent real bugs.
So don't disable it altogether, but go through the effort to suppress it
at the places where it currently happens.
Note that NM_PRAGMA_WARNING_DISABLE_DANGLING_POINTER macro only expands
to suppressing the warning with __GNUC__ equal to 12. The purpose is to
only suppress the warning where we know we want to. Hopefully other gcc
versions don't have this problem.
I guess, we could also write a NM_COMPILER_WARNING() check in
"m4/compiler_options.m4", to disable the warning if we detect it. But
that seems too cumbersome.
When you do
$ nmcli connection modify "$PROFILE" +ipv4.routing-rules 'uidrange 1000-1000 lookup 12345'
Error: failed to modify ipv4.routing-rules: rule is invalid: invalid priority.
That message seems confusing. Reword.
Make use of direct strv property in some cases. It doesn't work for
other cases yet, because they are implemented differently, and porting
them is more effort and needs to be done one by one.
The goal is to have a unified, standard implementation for our
properties. One that requires a minimal amount of property-specific
code. For strv properties, that is a bit more cumbersome, because
usually there are multiple C accessor functions. Still, make an effort
to have a "direct" strv property.
What this also gives, is that we no longer need to clone the strv array
for various operations. We know how to access the data, and can do it
directly without g_object_get()/g_object_set().
G_TYPE_STRV is the last property type in NMSetting that is implemented
by directly accessing the GObect property. Note that we have lots of
override, non-default implementations that still use GObject properties,
but I am talking here about properties that don't have a special
implementation and use a G_TYPE_STRV GObject property.
Add a "direct" implementation also for strv arrays.
The advantage is that we no longer call g_value_get() for various
operations, which requires a deep-copy of the strv array. The other
advantage is that we will get a unified approach for implementing strv
properties. In particular strv arrays need a lot of code to implement,
and most settings do it differently. By adding a general mechanism,
this code (and behavior) can be unified.
Showcase it on "match.interface-name".
IPv4:
routes
A list of IPv4 destination addresses, prefix length, optional IPv4
next hop addresses, optional route metric, optional attribute. The
valid syntax is: "ip[/prefix] [next-hop] [metric]
[attribute=val]...[,ip[/prefix]...]". For example "192.0.2.0/24
10.1.1.1 77, 198.51.100.0/24".
Various attributes are supported:
• "cwnd" - an unsigned 32 bit integer.
• "initcwnd" - an unsigned 32 bit integer.
• "initrwnd" - an unsigned 32 bit integer.
• "lock-cwnd" - a boolean value.
• "lock-initcwnd" - a boolean value.
• "lock-initrwnd" - a boolean value.
• "lock-mtu" - a boolean value.
• "lock-window" - a boolean value.
• "mtu" - an unsigned 32 bit integer.
• "onlink" - a boolean value.
• "scope" - an unsigned 8 bit integer. IPv4 only.
• "src" - an IPv4 address.
• "table" - an unsigned 32 bit integer. The default depends on
ipv4.route-table.
• "tos" - an unsigned 8 bit integer. IPv4 only.
• "type" - one of unicast, local, blackhole, unavailable,
prohibit. The default is unicast.
• "window" - an unsigned 32 bit integer.
For details see also `man ip-route`.
Format: a comma separated list of routes
IPv6:
routes
A list of IPv6 destination addresses, prefix length, optional IPv6
next hop addresses, optional route metric, optional attribute. The
valid syntax is: "ip[/prefix] [next-hop] [metric]
[attribute=val]...[,ip[/prefix]...]".
Various attributes are supported:
• "cwnd" - an unsigned 32 bit integer.
• "from" - an IPv6 address with optional prefix. IPv6 only.
• "initcwnd" - an unsigned 32 bit integer.
• "initrwnd" - an unsigned 32 bit integer.
• "lock-cwnd" - a boolean value.
• "lock-initcwnd" - a boolean value.
• "lock-initrwnd" - a boolean value.
• "lock-mtu" - a boolean value.
• "lock-window" - a boolean value.
• "mtu" - an unsigned 32 bit integer.
• "onlink" - a boolean value.
• "src" - an IPv6 address.
• "table" - an unsigned 32 bit integer. The default depends on
ipv6.route-table.
• "type" - one of unicast, local, blackhole, unavailable,
prohibit. The default is unicast.
• "window" - an unsigned 32 bit integer.
For details see also `man ip-route`.
Format: a comma separated list of routes
_nm_ip_route_attribute_validate_all() validates all attributes together.
As such, it calls to nm_ip_route_attribute_validate(), which in turn
validates one attribute at a time.
Such full validation needs to check that (potentially conflicting)
attributes are valid together. Hence, _nm_ip_route_attribute_validate_all()
needs again peek into the attributes.
Refactor the code, so that we can extract the pieces that we need and
not need to parse them twice.
First of all, all of NMVariantAttributeSpec is internal API. We only
expose the typedef itself as public API, but not its fields nor
their meaning. So we can change things.
Change "str_type" to "type_detail", so that it can work for any kind of
attribute, not only for strings. Usually, we want to avoid special
cases and treat all attributes the same, based on their GVariant type.
But sometimes, it is necessary to do something special with an
attribute. This is what the "type_detail" encodes, but it's not only
relevant for strings.
Usually the normalization (canonicalize) and validation of the IP
address string both requires to parse the string. As we always do
validation first, we can use the parsed address and don't need to parse
it a second time.
Order the fields by their size, to minimize the alignment gaps.
I guess, that doesn't matter because the alignment of the heap
allocation is larger than what we can safe here. Still, there is
on reason to do it any other way.
Also, it's not possible via API to set family/prefix to values outside
their range, so an 8bit integer is always sufficient. And we don't want
that invariant to change. We don't ever want to allow the caller to set
values that are clearly invalid, and will assert against that early (g_return()).
Point is, we can do this and there is no danger of future problems.
And even if we will support larger values, it's all an implementation
detail anyway.
In function '_nm_auto_g_free',
inlined from 'test_tc_config_tfilter_matchall_mirred' at src/libnm-core-impl/tests/test-setting.c:2955:24:
./src/libnm-glib-aux/nm-macros-internal.h:58:1: error: 'str' may be used uninitialized [-Werror=maybe-uninitialized]
58 | NM_AUTO_DEFINE_FCN_VOID0(void *, _nm_auto_g_free, g_free);
| ^
src/libnm-core-impl/tests/test-setting.c: In function 'test_tc_config_tfilter_matchall_mirred':
src/libnm-core-impl/tests/test-setting.c:2955:24: note: 'str' was declared here
2955 | gs_free char *str;
| ^
lto1: all warnings being treated as errors
lto-wrapper: fatal error: gcc returned 1 exit status
NMConnection is an interface, implemented by NMSimpleConnection
and NMRemoteConnection. A connection is basically a set of NMSetting
instances.
Usually you would expect that one NMSetting instance only gets added to
zero or one NMConnection. It seems a bit ugly, to have one setting tracked by
multiple NMConnection. Still, technically I am not aware of a single problem
with doing that, where it not for NMSimpleConnection:dispose() to clear the
secrets.
There is no need to clear the secrets of an NMSetting, when the
NMConnection gets destroyed. Either this destroys the NMSetting instance
right away (and NMSetting's destructor will clear the secrets anyway), or
somebody else (e.g. another NMConnection instance), keeps the setting
alive. In the latter case, it is wrong to clear the secrets at
this point.
This was done since commit 6a19e68a7d ('libnm-core: clear secrets from
NMSimpleConnection and NMSettingsConnection dispose()'), but let's stop
doing that.
This also causes problems in practice, see [1].
[1] https://gitlab.gnome.org/GNOME/gnome-control-center/-/merge_requests/1099#note_1334333https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/issues/876https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/1056
All callers of _nm_setting_get_private() got the offset from the
property info. Add a wrapper _nm_setting_get_private_field() that
takes the property info. This way, it can add some assertions.
Preferably, we embed the private struct in the GObject struct itself.
In the past, we didn't do that, because the struct was in public headers
and changing that would have been an ABI break. For those struct, we
still use g_type_class_add_private().
We have some structs, where the private struct is embedded. An
alternative to that would be, to not have the private struct at all,
like done for NMSettingOvsBridge.
Anyway. So for direct properties we need to capture the offset of the
field (in the private struct). We can either set the offset of the
private struct in _nm_setting_class_commit() to zero and let the field
offset include the private structure offset. Or, the offset of the
private struct is accounted during _nm_setting_class_commit().
Both approaches are basically the same. Just do it consistently. For no
particular reason, choose to set the offset of the private data to zero
for those types.
Several properties like "connection.type" are enum-like and only take a few
known values. We can use a NMRefString to share their instances.
Currently nm_setting_duplicate() does not yet explicitly handle direct properties.
But it should, because it can handle them more efficiently. If it would do that, it
would be very cheap to "copy" a NMRefString. But even with the current implementation
will the result be deduplicated.