libnm: add hook for setting direct string property

We want that our properties have little special cases and follow a
few common behaviors. For example, we have string properties, and those
should mostly behave the same (e.g. by being "direct-string"
properties).

That is already not fully enough, because we have slightly different
behaviors. For example, we have string properties that should have their
whitespace stripped, that should be ascii case down converted, that
should be normalized IP or MAC addresses. So far, that was expressed via
simple fields in NMSettInfoProperty, like NMSettInfoProperty's
direct_set_string_ascii_strdown field.

But that is not enough. In particular, for "wireguard.private-key" we
perform a different kind of normalization (base64 parsing, and taking
care not to leak secret in memory). It seems to special to add a boolean
flag "direct_set_string_wireguard_private_key".

Instead, add a hook that can cover that.

We need a hook, because we want one setter implementation throughout. Commonly,
we have at least two setters: the GObject set_property() and from D-Bus.
Both should call into the same underlying implementation, to avoid code
duplication. For that, the tweaked behavior must be "down", that is at
the deepest point in the call stack where we set the string. That's why
we need the hook. The alternative would be two special implementation
for GObject and D-Bus setters (and in the future we might add setters
from keyfile).
This commit is contained in:
Thomas Haller 2022-01-14 11:22:09 +01:00
parent 46f0bc4e70
commit 822042d9f9
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
3 changed files with 40 additions and 1 deletions

View file

@ -645,11 +645,16 @@ _property_direct_set_string(const NMSettInfoSetting *sett_info,
char **dst;
char *s;
nm_assert(property_info->property_type->direct_type == NM_VALUE_TYPE_STRING);
nm_assert(((!!property_info->direct_set_string_ascii_strdown)
+ (!!property_info->direct_set_string_strip)
+ (property_info->direct_set_string_mac_address_len > 0)
+ (property_info->direct_set_string_ip_address_addr_family != 0))
<= 1);
<= (property_info->direct_hook.set_string_fcn ? 0 : 1));
if (property_info->direct_hook.set_string_fcn) {
return property_info->direct_hook.set_string_fcn(sett_info, property_info, setting, src);
}
dst = _nm_setting_get_private(setting, sett_info, property_info->direct_offset);

View file

@ -4430,6 +4430,7 @@ test_setting_metadata(void)
GArray *property_types_data;
guint prop_idx_val;
gboolean can_set_including_default = FALSE;
gboolean can_have_direct_hook = FALSE;
int n_special_options;
g_assert(sip->name);
@ -4572,6 +4573,7 @@ test_setting_metadata(void)
g_assert(g_variant_type_equal(sip->property_type->dbus_type, "s"));
g_assert(sip->property_type->to_dbus_fcn
== _nm_setting_property_to_dbus_fcn_direct);
can_have_direct_hook = TRUE;
}
g_assert(sip->param_spec);
g_assert(sip->param_spec->value_type == G_TYPE_STRING);
@ -4596,6 +4598,9 @@ test_setting_metadata(void)
g_assert(sip->property_type->direct_type == NM_VALUE_TYPE_STRING);
}
if (!can_have_direct_hook)
g_assert(!sip->direct_hook.set_string_fcn);
n_special_options = (sip->direct_set_string_mac_address_len != 0)
+ (!!sip->direct_set_string_strip)
+ (!!sip->direct_set_string_ascii_strdown)

View file

@ -746,8 +746,37 @@ struct _NMSettInfoProperty {
GParamSpec *param_spec;
/* We want that our properties follow a small number of "default" types
* and behaviors. For example, we have int32 and string properties, but
* most properties of a certain type should behave in a similar way.
*
* That common behavior is realized via the property_type, which defines
* general behaviors for the property.
*
* Note that we still will need some property-specific additional tweaks.
* Of course, the name and param_spec are per-property. But below there are
* also flags and hooks, that can augment the behavior in the property_type.
* For example, the property_type in general might be of type string, but
* then we might want for some properties that the setter will strip
* whitespace. That is for example express with the flag direct_set_string_strip,
* which now is per-property-info, and no longer per-property-type.
*
* The distinction between those two is fixed. At the most extreme, we could
* move all fields from property_type to NMSettInfoProperty or we could move
* behavioral tweaks into the classes themselves. It's chosen this way so
* that we still have sensible common behaviors (string type), but minor
* tweaks are per property-info (and don't require a separate property-type). */
const NMSettInfoPropertType *property_type;
union {
/* Optional hook for direct string properties, this gets called when setting the string.
* Return whether the value changed. */
gboolean (*set_string_fcn)(const NMSettInfoSetting *sett_info,
const NMSettInfoProperty *property_info,
NMSetting *setting,
const char *src);
} direct_hook;
/* This only has meaning for direct properties (property_type->direct_type != NM_VALUE_TYPE_UNSPEC).
* In that case, this is the offset where _nm_setting_get_private() can find
* the direct location. */