all: merge branch 'th/various-for-wireguard-1'

https://github.com/NetworkManager/NetworkManager/pull/282
This commit is contained in:
Thomas Haller 2019-01-22 16:31:22 +01:00
commit 81da34eb1e
13 changed files with 544 additions and 296 deletions

View file

@ -102,10 +102,16 @@ setting_changed_cb (NMSetting *setting,
g_signal_emit (self, signals[CHANGED], 0);
}
static gboolean
_setting_release (gpointer key, gpointer value, gpointer user_data)
static void
_setting_release (NMConnection *connection, NMSetting *setting)
{
g_signal_handlers_disconnect_by_func (user_data, setting_changed_cb, value);
g_signal_handlers_disconnect_by_func (setting, setting_changed_cb, connection);
}
static gboolean
_setting_release_hfr (gpointer key, gpointer value, gpointer user_data)
{
_setting_release (user_data, value);
return TRUE;
}
@ -123,9 +129,10 @@ _nm_connection_add_setting (NMConnection *connection, NMSetting *setting)
setting_type = G_OBJECT_TYPE (setting);
if ((s_old = g_hash_table_lookup (priv->settings, _gtype_to_hash_key (setting_type))))
g_signal_handlers_disconnect_by_func (s_old, setting_changed_cb, connection);
_setting_release (connection, s_old);
g_hash_table_insert (priv->settings, _gtype_to_hash_key (setting_type), setting);
/* Listen for property changes so we can emit the 'changed' signal */
g_signal_connect (setting, "notify", (GCallback) setting_changed_cb, connection);
}
@ -409,7 +416,7 @@ _nm_connection_replace_settings (NMConnection *connection,
}
if (g_hash_table_size (priv->settings) > 0) {
g_hash_table_foreach_remove (priv->settings, _setting_release, connection);
g_hash_table_foreach_remove (priv->settings, _setting_release_hfr, connection);
changed = TRUE;
} else
changed = (settings != NULL);
@ -494,7 +501,7 @@ nm_connection_replace_settings_from_connection (NMConnection *connection,
new_priv = NM_CONNECTION_GET_PRIVATE (new_connection);
if ((changed = g_hash_table_size (priv->settings) > 0))
g_hash_table_foreach_remove (priv->settings, _setting_release, connection);
g_hash_table_foreach_remove (priv->settings, _setting_release_hfr, connection);
if (g_hash_table_size (new_priv->settings)) {
g_hash_table_iter_init (&iter, new_priv->settings);
@ -523,7 +530,7 @@ nm_connection_clear_settings (NMConnection *connection)
priv = NM_CONNECTION_GET_PRIVATE (connection);
if (g_hash_table_size (priv->settings) > 0) {
g_hash_table_foreach_remove (priv->settings, _setting_release, connection);
g_hash_table_foreach_remove (priv->settings, _setting_release_hfr, connection);
g_signal_emit (connection, signals[CHANGED], 0);
}
}
@ -1832,26 +1839,14 @@ nm_connection_need_secrets (NMConnection *connection,
void
nm_connection_clear_secrets (NMConnection *connection)
{
GHashTableIter iter;
NMSetting *setting;
g_return_if_fail (NM_IS_CONNECTION (connection));
g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (connection)->settings);
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting)) {
g_signal_handlers_block_by_func (setting, (GCallback) setting_changed_cb, connection);
_nm_setting_clear_secrets (setting);
g_signal_handlers_unblock_by_func (setting, (GCallback) setting_changed_cb, connection);
}
g_signal_emit (connection, signals[SECRETS_CLEARED], 0);
return nm_connection_clear_secrets_with_flags (connection, NULL, NULL);
}
/**
* nm_connection_clear_secrets_with_flags:
* @connection: the #NMConnection
* @func: (scope call): function to be called to determine whether a
* specific secret should be cleared or not
* @func: (scope call): (allow-none): function to be called to determine whether a
* specific secret should be cleared or not. If %NULL, all secrets are cleared.
* @user_data: caller-supplied data passed to @func
*
* Clears and frees secrets determined by @func.
@ -1869,7 +1864,7 @@ nm_connection_clear_secrets_with_flags (NMConnection *connection,
g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (connection)->settings);
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting)) {
g_signal_handlers_block_by_func (setting, (GCallback) setting_changed_cb, connection);
_nm_setting_clear_secrets_with_flags (setting, func, user_data);
_nm_setting_clear_secrets (setting, func, user_data);
g_signal_handlers_unblock_by_func (setting, (GCallback) setting_changed_cb, connection);
}
@ -2973,7 +2968,7 @@ nm_connection_private_free (NMConnectionPrivate *priv)
{
NMConnection *self = priv->self;
g_hash_table_foreach_remove (priv->settings, _setting_release, self);
g_hash_table_foreach_remove (priv->settings, _setting_release_hfr, self);
g_hash_table_destroy (priv->settings);
g_free (priv->path);

View file

@ -48,10 +48,9 @@ typedef enum NMSettingUpdateSecretResult {
NMSettingUpdateSecretResult _nm_setting_update_secrets (NMSetting *setting,
GVariant *secrets,
GError **error);
gboolean _nm_setting_clear_secrets (NMSetting *setting);
gboolean _nm_setting_clear_secrets_with_flags (NMSetting *setting,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data);
gboolean _nm_setting_clear_secrets (NMSetting *setting,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data);
/* The property of the #NMSetting should be considered during comparisons that
* use the %NM_SETTING_COMPARE_FLAG_INFERRABLE flag. Properties that don't have

View file

@ -813,29 +813,43 @@ compare_property (const NMSettInfoSetting *sett_info,
}
static gboolean
clear_secrets_with_flags (NMSetting *setting,
GParamSpec *pspec,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data)
clear_secrets (const NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data)
{
NMSettingVpnPrivate *priv = NM_SETTING_VPN_GET_PRIVATE (setting);
GParamSpec *prop_spec = sett_info->property_infos[property_idx].param_spec;
GHashTableIter iter;
const char *secret;
gboolean changed = TRUE;
if (priv->secrets == NULL)
if ( !prop_spec
|| !NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_SECRET))
return FALSE;
nm_assert (nm_streq (prop_spec->name, NM_SETTING_VPN_SECRETS));
if (!priv->secrets)
return FALSE;
/* Iterate through secrets hash and check each entry */
g_hash_table_iter_init (&iter, priv->secrets);
while (g_hash_table_iter_next (&iter, (gpointer) &secret, NULL)) {
NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
nm_setting_get_secret_flags (setting, secret, &flags, NULL);
if (func (setting, pspec->name, flags, user_data) == TRUE) {
g_hash_table_iter_remove (&iter);
changed = TRUE;
}
if (func) {
NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
if (!nm_setting_get_secret_flags (setting, secret, &flags, NULL))
nm_assert_not_reached ();
if (!func (setting, secret, flags, user_data))
continue;
} else
nm_assert (nm_setting_get_secret_flags (setting, secret, NULL, NULL));
g_hash_table_iter_remove (&iter);
changed = TRUE;
}
if (changed)
@ -963,13 +977,13 @@ nm_setting_vpn_class_init (NMSettingVpnClass *klass)
object_class->set_property = set_property;
object_class->finalize = finalize;
setting_class->verify = verify;
setting_class->update_one_secret = update_one_secret;
setting_class->get_secret_flags = get_secret_flags;
setting_class->set_secret_flags = set_secret_flags;
setting_class->need_secrets = need_secrets;
setting_class->compare_property = compare_property;
setting_class->clear_secrets_with_flags = clear_secrets_with_flags;
setting_class->verify = verify;
setting_class->update_one_secret = update_one_secret;
setting_class->get_secret_flags = get_secret_flags;
setting_class->set_secret_flags = set_secret_flags;
setting_class->need_secrets = need_secrets;
setting_class->compare_property = compare_property;
setting_class->clear_secrets = clear_secrets;
/**
* NMSettingVpn:service-type:

View file

@ -539,12 +539,16 @@ _nm_sett_info_setting_get_property_info (const NMSettInfoSetting *sett_info,
const NMSettInfoSetting *
_nm_setting_class_get_sett_info (NMSettingClass *setting_class)
{
if ( NM_IS_SETTING_CLASS (setting_class)
&& setting_class->setting_info) {
nm_assert (setting_class->setting_info->meta_type < G_N_ELEMENTS (_sett_info_settings));
return &_sett_info_settings[setting_class->setting_info->meta_type];
}
return NULL;
const NMSettInfoSetting *sett_info;
if ( !NM_IS_SETTING_CLASS (setting_class)
|| !setting_class->setting_info)
return NULL;
nm_assert (setting_class->setting_info->meta_type < G_N_ELEMENTS (_sett_info_settings));
sett_info = &_sett_info_settings[setting_class->setting_info->meta_type];
nm_assert (sett_info->setting_class == setting_class);
return sett_info;
}
/*****************************************************************************/
@ -876,53 +880,41 @@ _nm_setting_new_from_dbus (GType setting_type,
}
for (i = 0; i < sett_info->property_infos_len; i++) {
const NMSettInfoProperty *property = &sett_info->property_infos[i];
const NMSettInfoProperty *property_info = &sett_info->property_infos[i];
gs_unref_variant GVariant *value = NULL;
gs_free_error GError *local = NULL;
if (property->param_spec && !(property->param_spec->flags & G_PARAM_WRITABLE))
if ( property_info->param_spec
&& !(property_info->param_spec->flags & G_PARAM_WRITABLE))
continue;
value = g_variant_lookup_value (setting_dict, property->name, NULL);
value = g_variant_lookup_value (setting_dict, property_info->name, NULL);
if (value && keys)
g_hash_table_remove (keys, property->name);
g_hash_table_remove (keys, property_info->name);
if (value && property->set_func) {
if ( value
&& property_info->set_func) {
if (!g_variant_type_equal (g_variant_get_type (value), property->dbus_type)) {
if (!g_variant_type_equal (g_variant_get_type (value), property_info->dbus_type)) {
/* for backward behavior, fail unless best-effort is chosen. */
if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT))
continue;
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("can't set property of type '%s' from value of type '%s'"),
property->dbus_type ?
g_variant_type_peek_string (property->dbus_type) :
property->param_spec ?
g_type_name (property->param_spec->value_type) : "(unknown)",
property_info->dbus_type ?
g_variant_type_peek_string (property_info->dbus_type) :
property_info->param_spec ?
g_type_name (property_info->param_spec->value_type) : "(unknown)",
g_variant_get_type_string (value));
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name);
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
return NULL;
}
if (!property->set_func (setting,
connection_dict,
property->name,
value,
parse_flags,
&local)) {
if (!NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT))
continue;
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("failed to set property: %s"),
local->message);
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name);
return NULL;
}
} else if (!value && property->not_set_func) {
if (!property->not_set_func (setting,
if (!property_info->set_func (setting,
connection_dict,
property->name,
property_info->name,
value,
parse_flags,
&local)) {
if (!NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT))
@ -930,35 +922,52 @@ _nm_setting_new_from_dbus (GType setting_type,
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("failed to set property: %s"),
local->message);
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name);
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
return NULL;
}
} else if (value && property->param_spec) {
} else if ( !value
&& property_info->not_set_func) {
if (!property_info->not_set_func (setting,
connection_dict,
property_info->name,
parse_flags,
&local)) {
if (!NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT))
continue;
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("failed to set property: %s"),
local->message);
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
return NULL;
}
} else if ( value
&& property_info->param_spec) {
nm_auto_unset_gvalue GValue object_value = G_VALUE_INIT;
g_value_init (&object_value, property->param_spec->value_type);
if (!set_property_from_dbus (property, value, &object_value)) {
g_value_init (&object_value, property_info->param_spec->value_type);
if (!set_property_from_dbus (property_info, value, &object_value)) {
/* for backward behavior, fail unless best-effort is chosen. */
if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT))
continue;
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("can't set property of type '%s' from value of type '%s'"),
property->dbus_type ?
g_variant_type_peek_string (property->dbus_type) :
property->param_spec ?
g_type_name (property->param_spec->value_type) : "(unknown)",
property_info->dbus_type
? g_variant_type_peek_string (property_info->dbus_type)
: ( property_info->param_spec
? g_type_name (property_info->param_spec->value_type)
: "(unknown)"),
g_variant_get_type_string (value));
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name);
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
return NULL;
}
if (!nm_g_object_set_property (G_OBJECT (setting), property->param_spec->name, &object_value, &local)) {
if (!nm_g_object_set_property (G_OBJECT (setting), property_info->param_spec->name, &object_value, &local)) {
if (!NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT))
continue;
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("can not set property: %s"),
local->message);
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name);
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property_info->name);
return NULL;
}
}
@ -1065,34 +1074,18 @@ _gobject_copy_property (GObject *src,
g_object_set_property (dst, property_name, &value);
}
/**
* nm_setting_duplicate:
* @setting: the #NMSetting to duplicate
*
* Duplicates a #NMSetting.
*
* Returns: (transfer full): a new #NMSetting containing the same properties and values as the
* source #NMSetting
**/
NMSetting *
nm_setting_duplicate (NMSetting *setting)
static void
duplicate_copy_properties (const NMSettInfoSetting *sett_info,
NMSetting *src,
NMSetting *dst)
{
const NMSettInfoSetting *sett_info;
GObject *dup;
g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
dup = g_object_new (G_OBJECT_TYPE (setting), NULL);
sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting));
if (sett_info->detail.gendata_info) {
GenData *gendata = _gendata_hash (setting, FALSE);
GenData *gendata = _gendata_hash (src, FALSE);
if ( gendata
&& g_hash_table_size (gendata->hash) > 0) {
GHashTableIter iter;
GHashTable *h = _gendata_hash (NM_SETTING (dup), TRUE)->hash;
GHashTable *h = _gendata_hash (dst, TRUE)->hash;
const char *key;
GVariant *val;
@ -1110,29 +1103,58 @@ nm_setting_duplicate (NMSetting *setting)
guint i;
for (i = 0; i < sett_info->property_infos_len; i++) {
GParamSpec *prop_spec = sett_info->property_infos[i].param_spec;
const NMSettInfoProperty *property_info = &sett_info->property_infos[i];
if (!prop_spec)
continue;
if ((prop_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) != G_PARAM_WRITABLE)
continue;
if (property_info->param_spec) {
if ((property_info->param_spec->flags & (G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY)) != G_PARAM_WRITABLE)
continue;
if (!frozen) {
g_object_freeze_notify (dup);
frozen = TRUE;
if (!frozen) {
g_object_freeze_notify (G_OBJECT (dst));
frozen = TRUE;
}
_gobject_copy_property (G_OBJECT (src),
G_OBJECT (dst),
property_info->param_spec->name,
G_PARAM_SPEC_VALUE_TYPE (property_info->param_spec));
continue;
}
_gobject_copy_property (G_OBJECT (setting),
dup,
prop_spec->name,
G_PARAM_SPEC_VALUE_TYPE (prop_spec));
}
if (frozen)
g_object_thaw_notify (dup);
g_object_thaw_notify (G_OBJECT (dst));
}
}
return NM_SETTING (dup);
/**
* nm_setting_duplicate:
* @setting: the #NMSetting to duplicate
*
* Duplicates a #NMSetting.
*
* Returns: (transfer full): a new #NMSetting containing the same properties and values as the
* source #NMSetting
**/
NMSetting *
nm_setting_duplicate (NMSetting *setting)
{
const NMSettInfoSetting *sett_info;
NMSettingClass *klass;
NMSetting *dst;
g_return_val_if_fail (NM_IS_SETTING (setting), NULL);
klass = NM_SETTING_GET_CLASS (setting);
nm_assert (NM_IS_SETTING_CLASS (klass));
nm_assert (klass->duplicate_copy_properties);
dst = g_object_new (G_TYPE_FROM_CLASS (klass), NULL);
sett_info = _nm_setting_class_get_sett_info (klass);
nm_assert (sett_info);
klass->duplicate_copy_properties (sett_info, setting, dst);
return dst;
}
/**
@ -1818,81 +1840,47 @@ _nm_setting_aggregate (NMSetting *setting,
return FALSE;
}
/**
* _nm_setting_clear_secrets:
* @setting: the #NMSetting
*
* Resets and clears any secrets in the setting. Secrets should be added to the
* setting only when needed, and cleared immediately after use to prevent
* leakage of information.
*
* Returns: %TRUE if the setting changed at all
**/
gboolean
_nm_setting_clear_secrets (NMSetting *setting)
{
const NMSettInfoSetting *sett_info;
gboolean changed = FALSE;
guint i;
g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting));
for (i = 0; i < sett_info->property_infos_len; i++) {
GParamSpec *prop_spec = sett_info->property_infos[i].param_spec;
if (!prop_spec)
continue;
if (prop_spec->flags & NM_SETTING_PARAM_SECRET) {
GValue value = G_VALUE_INIT;
g_value_init (&value, prop_spec->value_type);
g_object_get_property (G_OBJECT (setting), prop_spec->name, &value);
if (!g_param_value_defaults (prop_spec, &value)) {
g_param_value_set_default (prop_spec, &value);
g_object_set_property (G_OBJECT (setting), prop_spec->name, &value);
changed = TRUE;
}
g_value_unset (&value);
}
}
return changed;
}
static gboolean
clear_secrets_with_flags (NMSetting *setting,
GParamSpec *pspec,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data)
clear_secrets (const NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data)
{
NMSettingSecretFlags flags = NM_SETTING_SECRET_FLAG_NONE;
gboolean changed = FALSE;
GParamSpec *param_spec = sett_info->property_infos[property_idx].param_spec;
g_return_val_if_fail (!NM_IS_SETTING_VPN (setting), FALSE);
if (!param_spec)
return FALSE;
/* Clear the secret if the user function says to do so */
if (!nm_setting_get_secret_flags (setting, pspec->name, &flags, NULL))
g_return_val_if_reached (FALSE);
if (!NM_FLAGS_HAS (param_spec->flags, NM_SETTING_PARAM_SECRET))
return FALSE;
if (func (setting, pspec->name, flags, user_data) == TRUE) {
GValue value = G_VALUE_INIT;
if (func) {
if (!nm_setting_get_secret_flags (setting, param_spec->name, &flags, NULL))
nm_assert_not_reached ();
if (!func (setting, param_spec->name, flags, user_data))
return FALSE;
} else
nm_assert (nm_setting_get_secret_flags (setting, param_spec->name, NULL, NULL));
g_value_init (&value, pspec->value_type);
g_object_get_property (G_OBJECT (setting), pspec->name, &value);
if (!g_param_value_defaults (pspec, &value)) {
g_param_value_set_default (pspec, &value);
g_object_set_property (G_OBJECT (setting), pspec->name, &value);
changed = TRUE;
}
g_value_unset (&value);
{
nm_auto_unset_gvalue GValue value = G_VALUE_INIT;
g_value_init (&value, param_spec->value_type);
g_object_get_property (G_OBJECT (setting), param_spec->name, &value);
if (g_param_value_defaults (param_spec, &value))
return FALSE;
g_param_value_set_default (param_spec, &value);
g_object_set_property (G_OBJECT (setting), param_spec->name, &value);
}
return changed;
return TRUE;
}
/**
* _nm_setting_clear_secrets_with_flags:
* _nm_setting_clear_secrets:
* @setting: the #NMSetting
* @func: (scope call): function to be called to determine whether a
* specific secret should be cleared or not
@ -1903,31 +1891,30 @@ clear_secrets_with_flags (NMSetting *setting,
* Returns: %TRUE if the setting changed at all
**/
gboolean
_nm_setting_clear_secrets_with_flags (NMSetting *setting,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data)
_nm_setting_clear_secrets (NMSetting *setting,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data)
{
const NMSettInfoSetting *sett_info;
gboolean changed = FALSE;
guint i;
gboolean (*my_clear_secrets) (const struct _NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data);
g_return_val_if_fail (NM_IS_SETTING (setting), FALSE);
g_return_val_if_fail (func != NULL, FALSE);
my_clear_secrets = NM_SETTING_GET_CLASS (setting)->clear_secrets;
sett_info = _nm_setting_class_get_sett_info (NM_SETTING_GET_CLASS (setting));
for (i = 0; i < sett_info->property_infos_len; i++) {
GParamSpec *prop_spec = sett_info->property_infos[i].param_spec;
if (!prop_spec)
continue;
if (!NM_FLAGS_HAS (prop_spec->flags, NM_SETTING_PARAM_SECRET))
continue;
changed |= NM_SETTING_GET_CLASS (setting)->clear_secrets_with_flags (setting,
prop_spec,
func,
user_data);
changed |= my_clear_secrets (sett_info,
i,
setting,
func,
user_data);
}
return changed;
}
@ -2579,11 +2566,12 @@ nm_setting_class_init (NMSettingClass *setting_class)
object_class->get_property = get_property;
object_class->finalize = finalize;
setting_class->update_one_secret = update_one_secret;
setting_class->get_secret_flags = get_secret_flags;
setting_class->set_secret_flags = set_secret_flags;
setting_class->compare_property = compare_property;
setting_class->clear_secrets_with_flags = clear_secrets_with_flags;
setting_class->update_one_secret = update_one_secret;
setting_class->get_secret_flags = get_secret_flags;
setting_class->set_secret_flags = set_secret_flags;
setting_class->compare_property = compare_property;
setting_class->clear_secrets = clear_secrets;
setting_class->duplicate_copy_properties = duplicate_copy_properties;
/**
* NMSetting:name:

View file

@ -200,10 +200,12 @@ typedef struct {
NMSettingSecretFlags flags,
GError **error);
gboolean (*clear_secrets_with_flags) (NMSetting *setting,
GParamSpec *pspec,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data);
/*< private >*/
gboolean (*clear_secrets) (const struct _NMSettInfoSetting *sett_info,
guint property_idx,
NMSetting *setting,
NMSettingClearSecretsWithFlagsFn func,
gpointer user_data);
/* compare_property() returns a ternary, where DEFAULT means that the property should not
* be compared due to the compare @flags. A TRUE/FALSE result means that the property is
@ -218,11 +220,16 @@ typedef struct {
NMSetting *other,
NMSettingCompareFlags flags);
/*< private >*/
void (*duplicate_copy_properties) (const struct _NMSettInfoSetting *sett_info,
NMSetting *src,
NMSetting *dst);
/*< private >*/
const struct _NMMetaSettingInfo *setting_info;
/*< private >*/
gpointer padding[6];
gpointer padding[5];
} NMSettingClass;
/**

View file

@ -102,6 +102,7 @@ typedef struct {
union {
guint8 addr_ptr[1];
in_addr_t addr4;
struct in_addr addr4_struct;
struct in6_addr addr6;
/* NMIPAddr is really a union for IP addresses.
@ -255,10 +256,12 @@ nm_memdup (gconstpointer data, gsize size)
static inline char *
_nm_strndup_a_step (char *s, const char *str, gsize len)
{
NM_PRAGMA_WARNING_DISABLE ("-Wstringop-truncation");
if (len > 0)
strncpy (s, str, len);
s[len] = '\0';
return s;
NM_PRAGMA_WARNING_REENABLE;
}
/* Similar to g_strndup(), however, if the string (including the terminating
@ -269,7 +272,12 @@ _nm_strndup_a_step (char *s, const char *str, gsize len)
*
* In case malloc() is necessary, @out_str_free will be set (this string
* must be freed afterwards). It is permissible to pass %NULL as @out_str_free,
* if you ensure that len < alloca_maxlen. */
* if you ensure that len < alloca_maxlen.
*
* Note that just like g_strndup(), this always returns a buffer with @len + 1
* bytes, even if strlen(@str) is shorter than that (NUL terminated early). We fill
* the buffer with strncpy(), which means, that @str is copied up to the first
* NUL character and then filled with NUL characters. */
#define nm_strndup_a(alloca_maxlen, str, len, out_str_free) \
({ \
const gsize _alloca_maxlen = (alloca_maxlen); \

View file

@ -152,6 +152,58 @@ test_nm_strdup_int (void)
/*****************************************************************************/
static void
test_nm_strndup_a (void)
{
int run;
for (run = 0; run < 20; run++) {
gs_free char *input = NULL;
char ch;
gsize i, l;
input = g_strnfill (nmtst_get_rand_int () % 20, 'x');
for (i = 0; input[i]; i++) {
while ((ch = ((char) nmtst_get_rand_int ())) == '\0') {
/* repeat. */
}
input[i] = ch;
}
{
gs_free char *dup_free = NULL;
const char *dup;
l = strlen (input) + 1;
dup = nm_strndup_a (10, input, l - 1, &dup_free);
g_assert_cmpstr (dup, ==, input);
if (strlen (dup) < 10)
g_assert (!dup_free);
else
g_assert (dup == dup_free);
}
{
gs_free char *dup_free = NULL;
const char *dup;
l = nmtst_get_rand_int () % 23;
dup = nm_strndup_a (10, input, l, &dup_free);
g_assert (strncmp (dup, input, l) == 0);
g_assert (strlen (dup) <= l);
if (l < 10)
g_assert (!dup_free);
else
g_assert (dup == dup_free);
if (strlen (input) < l)
g_assert (nm_utils_memeqzero (&dup[strlen (input)], l - strlen (input)));
}
}
}
/*****************************************************************************/
NMTST_DEFINE ();
int main (int argc, char **argv)
@ -162,6 +214,7 @@ int main (int argc, char **argv)
g_test_add_func ("/general/test_nmhash", test_nmhash);
g_test_add_func ("/general/test_nm_make_strv", test_make_strv);
g_test_add_func ("/general/test_nm_strdup_int", test_nm_strdup_int);
g_test_add_func ("/general/test_nm_strndup_a", test_nm_strndup_a);
return g_test_run ();
}

View file

@ -481,30 +481,6 @@ static struct nl_sock *_genl_sock (NMLinuxPlatform *platform);
/*****************************************************************************/
static int
_sock_addr_set_unaligned (NMSockAddrUnion *dst,
gconstpointer src,
gsize src_len)
{
int f_expected;
struct sockaddr sa;
if (src_len == sizeof (struct sockaddr_in))
f_expected = AF_INET;
else if (src_len == sizeof (struct sockaddr_in6))
f_expected = AF_INET6;
else
return AF_UNSPEC;
memcpy (&sa.sa_family, &((struct sockaddr *) src)->sa_family, sizeof (sa.sa_family));
if (sa.sa_family != f_expected)
return AF_UNSPEC;
memcpy (dst, src, src_len);
return f_expected;
}
/*****************************************************************************/
static int
wait_for_nl_response_to_nmerr (WaitForNlResponseResult seq_result)
{
@ -2038,11 +2014,11 @@ _wireguard_update_from_peers_nla (CList *peers,
nm_explicit_bzero (nla_data (tb[WGPEER_A_PRESHARED_KEY]),
nla_len (tb[WGPEER_A_PRESHARED_KEY]));
}
if (tb[WGPEER_A_ENDPOINT]) {
_sock_addr_set_unaligned (&peer_c->data.endpoint,
nla_data (tb[WGPEER_A_ENDPOINT]),
nla_len (tb[WGPEER_A_ENDPOINT]));
}
nm_sock_addr_union_cpy_untrusted (&peer_c->data.endpoint,
tb[WGPEER_A_ENDPOINT] ? nla_data (tb[WGPEER_A_ENDPOINT]) : NULL,
tb[WGPEER_A_ENDPOINT] ? nla_len (tb[WGPEER_A_ENDPOINT]) : 0);
if (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL])
peer_c->data.persistent_keepalive_interval = nla_get_u64 (tb[WGPEER_A_PERSISTENT_KEEPALIVE_INTERVAL]);
if (tb[WGPEER_A_LAST_HANDSHAKE_TIME])
@ -2398,6 +2374,7 @@ _wireguard_create_change_nlmsgs (NMPlatform *platform,
const NMPlatformLnkWireGuard *lnk_wireguard,
const NMPWireGuardPeer *peers,
guint peers_len,
gboolean replace_peers,
GPtrArray **out_msgs)
{
gs_unref_ptrarray GPtrArray *msgs = NULL;
@ -2446,7 +2423,9 @@ again:
NLA_PUT (msg, WGDEVICE_A_PRIVATE_KEY, sizeof (lnk_wireguard->private_key), lnk_wireguard->private_key);
NLA_PUT_U16 (msg, WGDEVICE_A_LISTEN_PORT, lnk_wireguard->listen_port);
NLA_PUT_U32 (msg, WGDEVICE_A_FWMARK, lnk_wireguard->fwmark);
NLA_PUT_U32 (msg, WGDEVICE_A_FLAGS, WGDEVICE_F_REPLACE_PEERS);
NLA_PUT_U32 (msg, WGDEVICE_A_FLAGS,
replace_peers ? WGDEVICE_F_REPLACE_PEERS : ((guint32) 0u));
}
if (peers_len == 0)
@ -2483,15 +2462,16 @@ again:
if (nla_put_uint32 (msg, WGPEER_A_FLAGS, WGPEER_F_REPLACE_ALLOWEDIPS) < 0)
goto toobig_peers;
g_return_val_if_fail (NM_IN_SET (p->endpoint.sa.sa_family, AF_INET, AF_INET6), -NME_BUG);
if (nla_put (msg,
WGPEER_A_ENDPOINT,
p->endpoint.sa.sa_family == AF_INET
? sizeof (p->endpoint.in)
: sizeof (p->endpoint.in6),
&p->endpoint) < 0)
goto toobig_peers;
if (NM_IN_SET (p->endpoint.sa.sa_family, AF_INET, AF_INET6)) {
if (nla_put (msg,
WGPEER_A_ENDPOINT,
p->endpoint.sa.sa_family == AF_INET
? sizeof (p->endpoint.in)
: sizeof (p->endpoint.in6),
&p->endpoint) < 0)
goto toobig_peers;
} else
nm_assert (p->endpoint.sa.sa_family == AF_UNSPEC);
}
if (p->allowed_ips_len > 0) {
@ -2575,7 +2555,8 @@ link_wireguard_change (NMPlatform *platform,
int ifindex,
const NMPlatformLnkWireGuard *lnk_wireguard,
const NMPWireGuardPeer *peers,
guint peers_len)
guint peers_len,
gboolean replace_peers)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
gs_unref_ptrarray GPtrArray *msgs = NULL;
@ -2593,6 +2574,7 @@ link_wireguard_change (NMPlatform *platform,
lnk_wireguard,
peers,
peers_len,
replace_peers,
&msgs);
if (r < 0) {
_LOGW ("wireguard: set-device, cannot construct netlink message: %s", nm_strerror (r));

View file

@ -1997,8 +1997,9 @@ int
nm_platform_link_wireguard_change (NMPlatform *self,
int ifindex,
const NMPlatformLnkWireGuard *lnk_wireguard,
const struct _NMPWireGuardPeer *peers,
guint peers_len)
const NMPWireGuardPeer *peers,
guint peers_len,
gboolean replace_peers)
{
_CHECK_SELF (self, klass, -NME_BUG);
@ -2024,18 +2025,20 @@ nm_platform_link_wireguard_change (NMPlatform *self,
nm_utils_strbuf_append_str (&b, &len, "}");
}
_LOG3D ("link: change wireguard ifindex %d, %s, %u peers%s",
_LOG3D ("link: change wireguard ifindex %d, %s, %u peers%s%s",
ifindex,
nm_platform_lnk_wireguard_to_string (lnk_wireguard, buf_lnk, sizeof (buf_lnk)),
peers_len,
buf_peers);
buf_peers,
replace_peers ? " (replace-peers)" : " (update-peers)");
}
return klass->link_wireguard_change (self,
ifindex,
lnk_wireguard,
peers,
peers_len);
peers_len,
replace_peers);
}
/*****************************************************************************/
@ -5604,33 +5607,24 @@ nm_platform_wireguard_peer_to_string (const NMPWireGuardPeer *peer, char *buf, g
{
char *buf0 = buf;
gs_free char *public_key_b64 = NULL;
char s_endpoint[NM_UTILS_INET_ADDRSTRLEN + 100];
char s_sockaddr[NM_UTILS_INET_ADDRSTRLEN + 100];
char s_endpoint[20 + sizeof (s_sockaddr)];
char s_addr[NM_UTILS_INET_ADDRSTRLEN];
char s_scope_id[40];
guint i;
nm_utils_to_string_buffer_init (&buf, &len);
if (peer->endpoint.sa.sa_family == AF_INET) {
public_key_b64 = g_base64_encode (peer->public_key, sizeof (peer->public_key));
if (peer->endpoint.sa.sa_family != AF_UNSPEC) {
nm_sprintf_buf (s_endpoint,
" endpoint %s:%u",
nm_utils_inet4_ntop (peer->endpoint.in.sin_addr.s_addr, s_addr),
(guint) htons (peer->endpoint.in.sin_port));
} else if (peer->endpoint.sa.sa_family == AF_INET6) {
if (peer->endpoint.in6.sin6_scope_id != 0)
nm_sprintf_buf (s_scope_id, "@%u", peer->endpoint.in6.sin6_scope_id);
else
s_scope_id[0] = '\0';
nm_sprintf_buf (s_endpoint,
" endpoint [%s]%s:%u",
nm_utils_inet6_ntop (&peer->endpoint.in6.sin6_addr, s_addr),
s_scope_id,
(guint) htons (peer->endpoint.in6.sin6_port));
" endpoint %s",
nm_sock_addr_union_to_string (&peer->endpoint,
s_sockaddr,
sizeof (s_sockaddr)));
} else
s_endpoint[0] = '\0';
public_key_b64 = g_base64_encode (peer->public_key, sizeof (peer->public_key));
nm_utils_strbuf_append (&buf, &len,
"public-key %s"
"%s" /* preshared-key */

View file

@ -831,7 +831,8 @@ typedef struct {
int ifindex,
const NMPlatformLnkWireGuard *lnk_wireguard,
const struct _NMPWireGuardPeer *peers,
guint peers_len);
guint peers_len,
gboolean replace_peers);
gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags, const NMPlatformLink **out_link);
gboolean (*link_vlan_change) (NMPlatform *self,
@ -1393,7 +1394,8 @@ int nm_platform_link_wireguard_change (NMPlatform *self,
int ifindex,
const NMPlatformLnkWireGuard *lnk_wireguard,
const struct _NMPWireGuardPeer *peers,
guint peers_len);
guint peers_len,
gboolean replace_peers);
const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address);

View file

@ -89,6 +89,192 @@ struct _NMPCache {
/*****************************************************************************/
int
nm_sock_addr_union_cmp (const NMSockAddrUnion *a, const NMSockAddrUnion *b)
{
nm_assert (!a || NM_IN_SET (a->sa.sa_family, AF_UNSPEC, AF_INET, AF_INET6));
nm_assert (!b || NM_IN_SET (b->sa.sa_family, AF_UNSPEC, AF_INET, AF_INET6));
NM_CMP_SELF (a, b);
NM_CMP_FIELD (a, b, sa.sa_family);
switch (a->sa.sa_family) {
case AF_INET:
NM_CMP_DIRECT (ntohl (a->in.sin_addr.s_addr), ntohl (b->in.sin_addr.s_addr));
NM_CMP_DIRECT (htons (a->in.sin_port), htons (b->in.sin_port));
break;
case AF_INET6:
NM_CMP_DIRECT_IN6ADDR (&a->in6.sin6_addr, &b->in6.sin6_addr);
NM_CMP_DIRECT (htons (a->in6.sin6_port), htons (b->in6.sin6_port));
NM_CMP_FIELD (a, b, in6.sin6_scope_id);
NM_CMP_FIELD (a, b, in6.sin6_flowinfo);
break;
}
return 0;
}
void
nm_sock_addr_union_hash_update (const NMSockAddrUnion *a, NMHashState *h)
{
if (!a) {
nm_hash_update_val (h, 1241364739u);
return;
}
nm_assert (NM_IN_SET (a->sa.sa_family, AF_UNSPEC, AF_INET, AF_INET6));
switch (a->sa.sa_family) {
case AF_INET:
nm_hash_update_vals (h,
a->in.sin_family,
a->in.sin_addr.s_addr,
a->in.sin_port);
return;
case AF_INET6:
nm_hash_update_vals (h,
a->in6.sin6_family,
a->in6.sin6_addr,
a->in6.sin6_port,
a->in6.sin6_scope_id,
a->in6.sin6_flowinfo);
return;
default:
nm_hash_update_val (h, a->sa.sa_family);
return;
}
}
/**
* nm_sock_addr_union_cpy:
* @dst: the destination #NMSockAddrUnion. It will always be fully initialized,
* to one of the address families AF_INET, AF_INET6, or AF_UNSPEC (in case of
* error).
* @src: (allow-none): the source buffer with an sockaddr to copy. It may be unaligned in
* memory. If not %NULL, the buffer must be at least large enough to contain
* sa.sa_family, and then, depending on sa.sa_family, it must be large enough
* to hold struct sockaddr_in or struct sockaddr_in6.
*
* @dst will always be fully initialized (including setting all un-used bytes to zero).
*/
void
nm_sock_addr_union_cpy (NMSockAddrUnion *dst,
gconstpointer src /* unaligned (const NMSockAddrUnion *) */)
{
struct sockaddr sa;
gsize src_len;
nm_assert (dst);
*dst = (NMSockAddrUnion) NM_SOCK_ADDR_UNION_INIT_UNSPEC;
if (!src)
return;
memcpy (&sa.sa_family, &((struct sockaddr *) src)->sa_family, sizeof (sa.sa_family));
if (sa.sa_family == AF_INET)
src_len = sizeof (struct sockaddr_in);
else if (sa.sa_family == AF_INET6)
src_len = sizeof (struct sockaddr_in6);
else
return;
memcpy (dst, src, src_len);
nm_assert (dst->sa.sa_family == sa.sa_family);
}
/**
* nm_sock_addr_union_cpy_untrusted:
* @dst: the destination #NMSockAddrUnion. It will always be fully initialized,
* to one of the address families AF_INET, AF_INET6, or AF_UNSPEC (in case of
* error).
* @src: the source buffer with an sockaddr to copy. It may be unaligned in
* memory.
* @src_len: the length of @src in bytes.
*
* The function requires @src_len to be either sizeof(struct sockaddr_in) or sizeof (struct sockaddr_in6).
* If that's the case, then @src will be interpreted as such structure (unaligned), and
* accessed. It will check sa.sa_family to match the expected sizes, and if it does, the
* struct will be copied.
*
* On any failure, @dst will be set to sa.sa_family AF_UNSPEC.
* @dst will always be fully initialized (including setting all un-used bytes to zero).
*/
void
nm_sock_addr_union_cpy_untrusted (NMSockAddrUnion *dst,
gconstpointer src /* unaligned (const NMSockAddrUnion *) */,
gsize src_len)
{
int f_expected;
struct sockaddr sa;
nm_assert (dst);
*dst = (NMSockAddrUnion) NM_SOCK_ADDR_UNION_INIT_UNSPEC;
if (src_len == sizeof (struct sockaddr_in))
f_expected = AF_INET;
else if (src_len == sizeof (struct sockaddr_in6))
f_expected = AF_INET6;
else
return;
memcpy (&sa.sa_family, &((struct sockaddr *) src)->sa_family, sizeof (sa.sa_family));
if (sa.sa_family != f_expected)
return;
memcpy (dst, src, src_len);
nm_assert (dst->sa.sa_family == sa.sa_family);
}
const char *
nm_sock_addr_union_to_string (const NMSockAddrUnion *sa,
char *buf,
gsize len)
{
char s_addr[NM_UTILS_INET_ADDRSTRLEN];
char s_scope_id[40];
if (!nm_utils_to_string_buffer_init_null (sa, &buf, &len))
return buf;
/* maybe we should use getnameinfo(), but here implement it ourself.
*
* We want to see the actual bytes for debugging (as we understand them),
* and now what getnameinfo() makes of it. Also, it's simpler this way. */
switch (sa->sa.sa_family) {
case AF_INET:
g_snprintf (buf, len,
"%s:%u",
nm_utils_inet4_ntop (sa->in.sin_addr.s_addr, s_addr),
(guint) htons (sa->in.sin_port));
break;
case AF_INET6:
g_snprintf (buf, len,
"[%s%s]:%u",
nm_utils_inet6_ntop (&sa->in6.sin6_addr, s_addr),
( sa->in6.sin6_scope_id != 0
? nm_sprintf_buf (s_scope_id, "%u", sa->in6.sin6_scope_id)
: ""),
(guint) htons (sa->in6.sin6_port));
break;
case AF_UNSPEC:
g_snprintf (buf, len, "unspec");
break;
default:
g_snprintf (buf, len,
"{addr-family:%u}",
(unsigned) sa->sa.sa_family);
break;
}
return buf;
}
/*****************************************************************************/
static const NMDedupMultiIdxTypeClass _dedup_multi_idx_type_class;
static void
@ -392,13 +578,9 @@ _wireguard_peer_hash_update (const NMPWireGuardPeer *peer,
peer->rx_bytes,
peer->tx_bytes,
peer->last_handshake_time.tv_sec,
peer->last_handshake_time.tv_nsec,
peer->endpoint.sa.sa_family);
peer->last_handshake_time.tv_nsec);
if (peer->endpoint.sa.sa_family == AF_INET)
nm_hash_update_val (h, peer->endpoint.in);
else if (peer->endpoint.sa.sa_family == AF_INET6)
nm_hash_update_val (h, peer->endpoint.in6);
nm_sock_addr_union_hash_update (&peer->endpoint, h);
for (i = 0; i < peer->allowed_ips_len; i++)
_wireguard_allowed_ip_hash_update (&peer->allowed_ips[i], h);
@ -422,10 +604,7 @@ _wireguard_peer_cmp (const NMPWireGuardPeer *a,
NM_CMP_FIELD_MEMCMP (a, b, public_key);
NM_CMP_FIELD_MEMCMP (a, b, preshared_key);
if (a->endpoint.sa.sa_family == AF_INET)
NM_CMP_FIELD_MEMCMP (a, b, endpoint.in);
else if (a->endpoint.sa.sa_family == AF_INET6)
NM_CMP_FIELD_MEMCMP (a, b, endpoint.in6);
NM_CMP_RETURN (nm_sock_addr_union_cmp (&a->endpoint, &b->endpoint));
for (i = 0; i < a->allowed_ips_len; i++) {
NM_CMP_RETURN (_wireguard_allowed_ip_cmp (&a->allowed_ips[i],

View file

@ -37,6 +37,32 @@ typedef union {
struct sockaddr_in6 in6;
} NMSockAddrUnion;
#define NM_SOCK_ADDR_UNION_INIT_UNSPEC \
{ \
.sa = { \
.sa_family = AF_UNSPEC, \
}, \
}
int nm_sock_addr_union_cmp (const NMSockAddrUnion *a,
const NMSockAddrUnion *b);
void nm_sock_addr_union_hash_update (const NMSockAddrUnion *a,
NMHashState *h);
void nm_sock_addr_union_cpy (NMSockAddrUnion *dst,
gconstpointer src /* unaligned (const NMSockAddrUnion *) */);
void nm_sock_addr_union_cpy_untrusted (NMSockAddrUnion *dst,
gconstpointer src /* unaligned (const NMSockAddrUnion *) */,
gsize src_len);
const char *nm_sock_addr_union_to_string (const NMSockAddrUnion *sa,
char *buf,
gsize len);
/*****************************************************************************/
typedef struct {
NMIPAddr addr;
guint8 family;

View file

@ -912,7 +912,8 @@ _test_wireguard_change (NMPlatform *platform,
ifindex,
&lnk_wireguard,
(const NMPWireGuardPeer *) peers->data,
peers->len);
peers->len,
TRUE);
g_assert (NMTST_NM_ERR_SUCCESS (r));
}