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.
Add helper wrappers around nm_g_object_set_property() that take a
native value, construct a GValue of the according type, and call
nm_g_object_set_property().
Commonly, the prefix is a string constant. We don't need to call
g_str_has_prefix() for that, which first requires strlen() on
the prefix. All the information is readily available.
Add a macro for that.
The state handling in add_and_activate_cb() and connect_device_cb() is
redundant to connected_state_cb() and in fact executed only if the
activation is really really really quick (which it never is).
Also, the return_text those implementations provide is different from
what connected_state_cb(), potentially confusing the users and adding
extra work for translators.
Not to mention extra lines of code, reading whose wastes our precious
time on the planet we could spend doing heroin instead.
Try to locate an existing connection before creating a new one when
handling "nmcli device wifi connect". This allows WPA-Enterprise
networks to be activated this way, consistent with the comment that this
command is equivalent to clicking on an SSID in a GUI client.
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".
glib has an base64 implementation, but g_base64_decode() et al. gives
no way to detect invalid encodings. All invalid codes are silently
ignored. That is not suitable for strictly validating user input.
Instead of reimplementing of copy-pasting the code from somewhere,
reuse systemd's unbase64mem().
But don't use "hexdecoct.h" directly. Instead, add a single accessor
function to our "nm-sd-utils-shared.h" gateway. We want to be careful
about which bits from systemd we use, because otherwise re-importing
systemd code becomes fragile as you don't know which relevant parts
changed.
For better or worse, we already pull in large parts of systemd sources.
I need a base64 decode implementation (because glib's g_base64_decode()
cannot reject invalid encodings). Instead of coming up with my own or
copy-paste if from somewhere, reuse systemd's unbase64mem().
But for that, make systemd's basic bits an independent static library
first because I will need it in libnm-core.
This doesn't really change anything except making "libnm-systemd-core.la"
an indpendent static library that could be used from "libnm-core". We
shall still be mindful about which internal code of systemd we use, and only
access functionality that is exposed via "systemd/nm-sd-utils-shared.h".
C11 provides _Generic(). Until now we used it when the compiler supports
it (in extended --std=gnu99 mode). In practice, now that we require C11
it should always be present.
We will drop compatibility code in the future. For now, just add a comment
and keep it. The reason is, that "shared/nm-utils/nm-macros-internal.h"
may be used by VPN plugins or applet, which may or may not yet bump to
C11. Keeping it for now, allows for an easier update.
We already import systemd code which is C11. To get this even
to build, we need workaround like patching import of <uchar.h>.
Also, the libraries from c-util and nettools are C11. We cannot even
compile them in C99 mode (and didn't do that either).
It's time to bump the version. We need C11 from now on (or better: gcc's
dialect of it).
Also, note that since nettools/nacd is not optional, we could not even
build NetworkManager without a C11 compiler. So, just use it everywhere.
In core ("src/"), we use "nm-logging.h" for all logging. This dispatches
for logging to syslog, glog or systemd-journald.
If we want to log from a shared component under "shared/", we need to
use a common logging function. Add "nm-utils/nm-logging-fwd.h" for
forward declaring the used logging mechaism.
The shared library will still need to link with "src/nm-logging.c"
or an alternative implementation, depending on whether it is used
inside core or not.
- 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.
This allows us to add a file "TODO.txt" in the top level directory.
This file is not intended to be merged to master, but keep track of
stuff that is still to do before merging a branch.
Let checkpatch.pl warn about the presence of such a file.