mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-08 11:50:22 +01:00
libnm-core: allow strict and relaxed error behavior for _nm_setting_new_from_dbus()
In some situations, we want strict checking of errors, for example when NetworkManager receives a new connection from a client, the connection must make sense as a whole (and since NetworkManager service is backward compatible to the clients and not the other way around, there is no excuse for sending invalid data to the server). In other situations, we want a best-effort behavior. Like when NetworkManager sends a connection to its clients, those clients want to extract as many properties as they understand, but in order to be forward compatible against newer server versions, invalid or unknown properties must be accepted. Previously, a mixture of both was done. Some issues caused a failure to create a new NMSetting, other invalid parts were just silently ignored or triggered a g_warning() in glib. Now allow for both. When doing strict-validation, be more strict and reject all unknown properties and catch when the user sets an invalid argument. On the other hand, allow for a best-effort mode that effectively cannot fail and will return a new NMSetting instance. For now, add NMSettingParseFlags so that the caller can choose the old behavior, strict parsing, or best effort. This patch doesn't have any externally visible change except that no more g_warnings will be emitted.
This commit is contained in:
parent
88655999df
commit
737c8cc532
10 changed files with 336 additions and 125 deletions
|
|
@ -232,6 +232,118 @@ validate_permissions_type (GVariant *variant, GError **error)
|
|||
return valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* _nm_connection_replace_settings:
|
||||
* @connection: a #NMConnection
|
||||
* @new_settings: a #GVariant of type %NM_VARIANT_TYPE_CONNECTION, with the new settings
|
||||
* @parse_flags: flags.
|
||||
* @error: location to store error, or %NULL
|
||||
*
|
||||
* Replaces @connection's settings with @new_settings (which must be
|
||||
* syntactically valid, and describe a known type of connection, but does not
|
||||
* need to result in a connection that passes nm_connection_verify()).
|
||||
*
|
||||
* Returns: %TRUE if connection was updated, %FALSE if @new_settings could not
|
||||
* be deserialized (in which case @connection will be unchanged).
|
||||
**/
|
||||
gboolean
|
||||
_nm_connection_replace_settings (NMConnection *connection,
|
||||
GVariant *new_settings,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error)
|
||||
{
|
||||
NMConnectionPrivate *priv;
|
||||
GVariantIter iter;
|
||||
const char *setting_name;
|
||||
GVariant *setting_dict;
|
||||
GSList *settings = NULL, *s;
|
||||
gboolean changed;
|
||||
|
||||
g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
|
||||
g_return_val_if_fail (g_variant_is_of_type (new_settings, NM_VARIANT_TYPE_CONNECTION), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
nm_assert (!NM_FLAGS_ANY (parse_flags, ~NM_SETTING_PARSE_FLAGS_ALL));
|
||||
nm_assert (!NM_FLAGS_ALL (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT | NM_SETTING_PARSE_FLAGS_BEST_EFFORT));
|
||||
|
||||
priv = NM_CONNECTION_GET_PRIVATE (connection);
|
||||
|
||||
if ( !NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT)
|
||||
&& !validate_permissions_type (new_settings, error))
|
||||
return FALSE;
|
||||
|
||||
g_variant_iter_init (&iter, new_settings);
|
||||
while (g_variant_iter_next (&iter, "{&s@a{sv}}", &setting_name, &setting_dict)) {
|
||||
gs_unref_variant GVariant *setting_dict_free = NULL;
|
||||
GError *local = NULL;
|
||||
NMSetting *setting;
|
||||
GType type;
|
||||
|
||||
setting_dict_free = setting_dict;
|
||||
|
||||
type = nm_setting_lookup_type (setting_name);
|
||||
if (type == G_TYPE_INVALID) {
|
||||
if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT))
|
||||
continue;
|
||||
g_set_error_literal (error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_INVALID_SETTING,
|
||||
_("unknown setting name"));
|
||||
g_prefix_error (error, "%s: ", setting_name);
|
||||
g_slist_free_full (settings, g_object_unref);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
for (s = settings; s; s = s->next) {
|
||||
if (G_OBJECT_TYPE (s->data) == type) {
|
||||
if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) {
|
||||
g_set_error_literal (error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_INVALID_SETTING,
|
||||
_("duplicate setting name"));
|
||||
g_prefix_error (error, "%s: ", setting_name);
|
||||
g_slist_free_full (settings, g_object_unref);
|
||||
return FALSE;
|
||||
}
|
||||
/* last wins. */
|
||||
g_object_unref (s->data);
|
||||
settings = g_slist_delete_link (settings, s);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
setting = _nm_setting_new_from_dbus (type, setting_dict, new_settings, parse_flags, &local);
|
||||
|
||||
if (!setting) {
|
||||
if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_BEST_EFFORT))
|
||||
continue;
|
||||
g_propagate_error (error, local);
|
||||
g_slist_free_full (settings, g_object_unref);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
settings = g_slist_prepend (settings, setting);
|
||||
}
|
||||
|
||||
if (g_hash_table_size (priv->settings) > 0) {
|
||||
g_hash_table_foreach_remove (priv->settings, _setting_release, connection);
|
||||
changed = TRUE;
|
||||
} else
|
||||
changed = (settings != NULL);
|
||||
|
||||
/* Note: @settings might be empty in which case the connection
|
||||
* has no NMSetting instances... which is fine, just something
|
||||
* to be aware of. */
|
||||
for (s = settings; s; s = s->next)
|
||||
_nm_connection_add_setting (connection, s->data);
|
||||
|
||||
g_slist_free (settings);
|
||||
|
||||
if (changed)
|
||||
g_signal_emit (connection, signals[CHANGED], 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_connection_replace_settings:
|
||||
* @connection: a #NMConnection
|
||||
|
|
@ -250,64 +362,7 @@ nm_connection_replace_settings (NMConnection *connection,
|
|||
GVariant *new_settings,
|
||||
GError **error)
|
||||
{
|
||||
NMConnectionPrivate *priv;
|
||||
GVariantIter iter;
|
||||
const char *setting_name;
|
||||
GVariant *setting_dict;
|
||||
GSList *settings = NULL, *s;
|
||||
gboolean changed;
|
||||
|
||||
g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
|
||||
g_return_val_if_fail (g_variant_is_of_type (new_settings, NM_VARIANT_TYPE_CONNECTION), FALSE);
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
|
||||
|
||||
priv = NM_CONNECTION_GET_PRIVATE (connection);
|
||||
|
||||
if (!validate_permissions_type (new_settings, error))
|
||||
return FALSE;
|
||||
|
||||
g_variant_iter_init (&iter, new_settings);
|
||||
while (g_variant_iter_next (&iter, "{&s@a{sv}}", &setting_name, &setting_dict)) {
|
||||
NMSetting *setting;
|
||||
GType type;
|
||||
|
||||
type = nm_setting_lookup_type (setting_name);
|
||||
if (type == G_TYPE_INVALID) {
|
||||
g_set_error_literal (error,
|
||||
NM_CONNECTION_ERROR,
|
||||
NM_CONNECTION_ERROR_INVALID_SETTING,
|
||||
_("unknown setting name"));
|
||||
g_prefix_error (error, "%s: ", setting_name);
|
||||
g_variant_unref (setting_dict);
|
||||
g_slist_free_full (settings, g_object_unref);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
setting = _nm_setting_new_from_dbus (type, setting_dict, new_settings, error);
|
||||
g_variant_unref (setting_dict);
|
||||
|
||||
if (!setting) {
|
||||
g_slist_free_full (settings, g_object_unref);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
settings = g_slist_prepend (settings, setting);
|
||||
}
|
||||
|
||||
if (g_hash_table_size (priv->settings) > 0) {
|
||||
g_hash_table_foreach_remove (priv->settings, _setting_release, connection);
|
||||
changed = TRUE;
|
||||
} else
|
||||
changed = (settings != NULL);
|
||||
|
||||
for (s = settings; s; s = s->next)
|
||||
_nm_connection_add_setting (connection, s->data);
|
||||
|
||||
g_slist_free (settings);
|
||||
|
||||
if (changed)
|
||||
g_signal_emit (connection, signals[CHANGED], 0);
|
||||
return TRUE;
|
||||
return _nm_connection_replace_settings (connection, new_settings, NM_SETTING_PARSE_FLAGS_NONE, error);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -100,6 +100,20 @@
|
|||
NM_SETTING_SECRET_FLAG_NOT_SAVED | \
|
||||
NM_SETTING_SECRET_FLAG_NOT_REQUIRED)
|
||||
|
||||
typedef enum { /*< skip >*/
|
||||
NM_SETTING_PARSE_FLAGS_NONE = 0,
|
||||
NM_SETTING_PARSE_FLAGS_STRICT = 1LL << 0,
|
||||
NM_SETTING_PARSE_FLAGS_BEST_EFFORT = 1LL << 1,
|
||||
|
||||
_NM_SETTING_PARSE_FLAGS_LAST,
|
||||
NM_SETTING_PARSE_FLAGS_ALL = ((_NM_SETTING_PARSE_FLAGS_LAST - 1) << 1) - 1,
|
||||
} NMSettingParseFlags;
|
||||
|
||||
gboolean _nm_connection_replace_settings (NMConnection *connection,
|
||||
GVariant *new_settings,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error);
|
||||
|
||||
guint32 _nm_setting_get_setting_priority (NMSetting *setting);
|
||||
|
||||
gboolean _nm_setting_get_property (NMSetting *setting, const char *name, GValue *value);
|
||||
|
|
|
|||
|
|
@ -1055,11 +1055,13 @@ find_virtual_interface_name (GVariant *connection_dict)
|
|||
return interface_name;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
nm_setting_connection_set_interface_name (NMSetting *setting,
|
||||
GVariant *connection_dict,
|
||||
const char *property,
|
||||
GVariant *value)
|
||||
GVariant *value,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error)
|
||||
{
|
||||
const char *interface_name;
|
||||
|
||||
|
|
@ -1074,12 +1076,16 @@ nm_setting_connection_set_interface_name (NMSetting *setting,
|
|||
g_object_set (G_OBJECT (setting),
|
||||
NM_SETTING_CONNECTION_INTERFACE_NAME, interface_name,
|
||||
NULL);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
nm_setting_connection_no_interface_name (NMSetting *setting,
|
||||
GVariant *connection_dict,
|
||||
const char *property)
|
||||
const char *property,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error)
|
||||
{
|
||||
const char *virtual_interface_name;
|
||||
|
||||
|
|
@ -1087,6 +1093,7 @@ nm_setting_connection_no_interface_name (NMSetting *setting,
|
|||
g_object_set (G_OBJECT (setting),
|
||||
NM_SETTING_CONNECTION_INTERFACE_NAME, virtual_interface_name,
|
||||
NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
|
|
|
|||
|
|
@ -2464,17 +2464,22 @@ get_property (GObject *object, guint prop_id,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
ip_gateway_set (NMSetting *setting,
|
||||
GVariant *connection_dict,
|
||||
const char *property,
|
||||
GVariant *value)
|
||||
GVariant *value,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error)
|
||||
{
|
||||
/* FIXME: properly handle errors */
|
||||
|
||||
/* Don't set from 'gateway' if we're going to use the gateway in 'addresses' */
|
||||
if (_nm_setting_use_legacy_property (setting, connection_dict, "addresses", "gateway"))
|
||||
return;
|
||||
return TRUE;
|
||||
|
||||
g_object_set (setting, property, g_variant_get_string (value, NULL), NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -313,19 +313,23 @@ ip4_addresses_get (NMSetting *setting,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
ip4_addresses_set (NMSetting *setting,
|
||||
GVariant *connection_dict,
|
||||
const char *property,
|
||||
GVariant *value)
|
||||
GVariant *value,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error)
|
||||
{
|
||||
GPtrArray *addrs;
|
||||
GVariant *s_ip4;
|
||||
char **labels, *gateway = NULL;
|
||||
int i;
|
||||
|
||||
/* FIXME: properly handle errors */
|
||||
|
||||
if (!_nm_setting_use_legacy_property (setting, connection_dict, "addresses", "address-data"))
|
||||
return;
|
||||
return TRUE;
|
||||
|
||||
addrs = nm_utils_ip4_addresses_from_variant (value, &gateway);
|
||||
|
||||
|
|
@ -344,6 +348,7 @@ ip4_addresses_set (NMSetting *setting,
|
|||
NULL);
|
||||
g_ptr_array_unref (addrs);
|
||||
g_free (gateway);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
|
|
@ -399,21 +404,26 @@ ip4_address_data_get (NMSetting *setting,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
ip4_address_data_set (NMSetting *setting,
|
||||
GVariant *connection_dict,
|
||||
const char *property,
|
||||
GVariant *value)
|
||||
GVariant *value,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error)
|
||||
{
|
||||
GPtrArray *addrs;
|
||||
|
||||
/* FIXME: properly handle errors */
|
||||
|
||||
/* Ignore 'address-data' if we're going to process 'addresses' */
|
||||
if (_nm_setting_use_legacy_property (setting, connection_dict, "addresses", "address-data"))
|
||||
return;
|
||||
return TRUE;
|
||||
|
||||
addrs = nm_utils_ip_addresses_from_variant (value, AF_INET);
|
||||
g_object_set (setting, NM_SETTING_IP_CONFIG_ADDRESSES, addrs, NULL);
|
||||
g_ptr_array_unref (addrs);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
|
|
@ -430,20 +440,25 @@ ip4_routes_get (NMSetting *setting,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
ip4_routes_set (NMSetting *setting,
|
||||
GVariant *connection_dict,
|
||||
const char *property,
|
||||
GVariant *value)
|
||||
GVariant *value,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error)
|
||||
{
|
||||
GPtrArray *routes;
|
||||
|
||||
/* FIXME: properly handle errors */
|
||||
|
||||
if (!_nm_setting_use_legacy_property (setting, connection_dict, "routes", "route-data"))
|
||||
return;
|
||||
return TRUE;
|
||||
|
||||
routes = nm_utils_ip4_routes_from_variant (value);
|
||||
g_object_set (setting, property, routes, NULL);
|
||||
g_ptr_array_unref (routes);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
|
|
@ -461,21 +476,26 @@ ip4_route_data_get (NMSetting *setting,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
ip4_route_data_set (NMSetting *setting,
|
||||
GVariant *connection_dict,
|
||||
const char *property,
|
||||
GVariant *value)
|
||||
GVariant *value,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error)
|
||||
{
|
||||
GPtrArray *routes;
|
||||
|
||||
/* FIXME: properly handle errors */
|
||||
|
||||
/* Ignore 'route-data' if we're going to process 'routes' */
|
||||
if (_nm_setting_use_legacy_property (setting, connection_dict, "routes", "route-data"))
|
||||
return;
|
||||
return TRUE;
|
||||
|
||||
routes = nm_utils_ip_routes_from_variant (value, AF_INET);
|
||||
g_object_set (setting, NM_SETTING_IP_CONFIG_ROUTES, routes, NULL);
|
||||
g_ptr_array_unref (routes);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -239,17 +239,21 @@ ip6_addresses_get (NMSetting *setting,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
ip6_addresses_set (NMSetting *setting,
|
||||
GVariant *connection_dict,
|
||||
const char *property,
|
||||
GVariant *value)
|
||||
GVariant *value,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error)
|
||||
{
|
||||
GPtrArray *addrs;
|
||||
char *gateway = NULL;
|
||||
|
||||
/* FIXME: properly handle errors */
|
||||
|
||||
if (!_nm_setting_use_legacy_property (setting, connection_dict, "addresses", "address-data"))
|
||||
return;
|
||||
return TRUE;
|
||||
|
||||
addrs = nm_utils_ip6_addresses_from_variant (value, &gateway);
|
||||
|
||||
|
|
@ -259,6 +263,7 @@ ip6_addresses_set (NMSetting *setting,
|
|||
NULL);
|
||||
g_ptr_array_unref (addrs);
|
||||
g_free (gateway);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
|
|
@ -276,21 +281,26 @@ ip6_address_data_get (NMSetting *setting,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
ip6_address_data_set (NMSetting *setting,
|
||||
GVariant *connection_dict,
|
||||
const char *property,
|
||||
GVariant *value)
|
||||
GVariant *value,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error)
|
||||
{
|
||||
GPtrArray *addrs;
|
||||
|
||||
/* FIXME: properly handle errors */
|
||||
|
||||
/* Ignore 'address-data' if we're going to process 'addresses' */
|
||||
if (_nm_setting_use_legacy_property (setting, connection_dict, "addresses", "address-data"))
|
||||
return;
|
||||
return TRUE;
|
||||
|
||||
addrs = nm_utils_ip_addresses_from_variant (value, AF_INET6);
|
||||
g_object_set (setting, NM_SETTING_IP_CONFIG_ADDRESSES, addrs, NULL);
|
||||
g_ptr_array_unref (addrs);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
|
|
@ -307,20 +317,25 @@ ip6_routes_get (NMSetting *setting,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
ip6_routes_set (NMSetting *setting,
|
||||
GVariant *connection_dict,
|
||||
const char *property,
|
||||
GVariant *value)
|
||||
GVariant *value,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error)
|
||||
{
|
||||
GPtrArray *routes;
|
||||
|
||||
/* FIXME: properly handle errors */
|
||||
|
||||
if (!_nm_setting_use_legacy_property (setting, connection_dict, "routes", "route-data"))
|
||||
return;
|
||||
return TRUE;
|
||||
|
||||
routes = nm_utils_ip6_routes_from_variant (value);
|
||||
g_object_set (setting, property, routes, NULL);
|
||||
g_ptr_array_unref (routes);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GVariant *
|
||||
|
|
@ -338,21 +353,26 @@ ip6_route_data_get (NMSetting *setting,
|
|||
return ret;
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
ip6_route_data_set (NMSetting *setting,
|
||||
GVariant *connection_dict,
|
||||
const char *property,
|
||||
GVariant *value)
|
||||
GVariant *value,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error)
|
||||
{
|
||||
GPtrArray *routes;
|
||||
|
||||
/* FIXME: properly handle errors */
|
||||
|
||||
/* Ignore 'route-data' if we're going to process 'routes' */
|
||||
if (_nm_setting_use_legacy_property (setting, connection_dict, "routes", "route-data"))
|
||||
return;
|
||||
return TRUE;
|
||||
|
||||
routes = nm_utils_ip_routes_from_variant (value, AF_INET6);
|
||||
g_object_set (setting, NM_SETTING_IP_CONFIG_ROUTES, routes, NULL);
|
||||
g_ptr_array_unref (routes);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -126,6 +126,7 @@ GVariant *_nm_setting_to_dbus (NMSetting *setting,
|
|||
NMSetting *_nm_setting_new_from_dbus (GType setting_type,
|
||||
GVariant *setting_dict,
|
||||
GVariant *connection_dict,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error);
|
||||
|
||||
typedef GVariant * (*NMSettingPropertyGetFunc) (NMSetting *setting,
|
||||
|
|
@ -133,13 +134,17 @@ typedef GVariant * (*NMSettingPropertyGetFunc) (NMSetting *setting,
|
|||
typedef GVariant * (*NMSettingPropertySynthFunc) (NMSetting *setting,
|
||||
NMConnection *connection,
|
||||
const char *property);
|
||||
typedef void (*NMSettingPropertySetFunc) (NMSetting *setting,
|
||||
typedef gboolean (*NMSettingPropertySetFunc) (NMSetting *setting,
|
||||
GVariant *connection_dict,
|
||||
const char *property,
|
||||
GVariant *value);
|
||||
typedef void (*NMSettingPropertyNotSetFunc) (NMSetting *setting,
|
||||
GVariant *value,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error);
|
||||
typedef gboolean (*NMSettingPropertyNotSetFunc) (NMSetting *setting,
|
||||
GVariant *connection_dict,
|
||||
const char *property);
|
||||
const char *property,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error);
|
||||
|
||||
void _nm_setting_class_add_dbus_only_property (NMSettingClass *setting_class,
|
||||
const char *property_name,
|
||||
|
|
|
|||
|
|
@ -692,16 +692,19 @@ _override_flags_get (NMSetting *setting, const char *property)
|
|||
return g_variant_new_uint32 (nm_setting_vlan_get_flags ((NMSettingVlan *) setting));
|
||||
}
|
||||
|
||||
static void
|
||||
static gboolean
|
||||
_override_flags_not_set (NMSetting *setting,
|
||||
GVariant *connection_dict,
|
||||
const char *property)
|
||||
GVariant *connection_dict,
|
||||
const char *property,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error)
|
||||
{
|
||||
/* we changed the default value for FLAGS. When an older client
|
||||
* doesn't serialize the property, we assume it is the old default. */
|
||||
g_object_set (G_OBJECT (setting),
|
||||
NM_SETTING_VLAN_FLAGS, (NMVlanFlags) 0,
|
||||
NULL);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static GSList *
|
||||
|
|
|
|||
|
|
@ -774,6 +774,7 @@ _nm_setting_to_dbus (NMSetting *setting, NMConnection *connection, NMConnectionS
|
|||
* mapping property names to values
|
||||
* @connection_dict: the #GVariant containing an %NM_VARIANT_TYPE_CONNECTION
|
||||
* dictionary mapping setting names to dictionaries.
|
||||
* @parse_flags: flags to determine behavior during parsing.
|
||||
* @error: location to store error, or %NULL
|
||||
*
|
||||
* Creates a new #NMSetting object and populates that object with the properties
|
||||
|
|
@ -790,16 +791,20 @@ NMSetting *
|
|||
_nm_setting_new_from_dbus (GType setting_type,
|
||||
GVariant *setting_dict,
|
||||
GVariant *connection_dict,
|
||||
NMSettingParseFlags parse_flags,
|
||||
GError **error)
|
||||
{
|
||||
NMSetting *setting;
|
||||
gs_unref_object NMSetting *setting = NULL;
|
||||
gs_unref_hashtable GHashTable *keys = NULL;
|
||||
const NMSettingProperty *properties;
|
||||
guint n_properties;
|
||||
guint i;
|
||||
guint i, n_properties;
|
||||
|
||||
g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (setting_type), NULL);
|
||||
g_return_val_if_fail (g_variant_is_of_type (setting_dict, NM_VARIANT_TYPE_SETTING), NULL);
|
||||
|
||||
nm_assert (!NM_FLAGS_ANY (parse_flags, ~NM_SETTING_PARSE_FLAGS_ALL));
|
||||
nm_assert (!NM_FLAGS_ALL (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT | NM_SETTING_PARSE_FLAGS_BEST_EFFORT));
|
||||
|
||||
/* connection_dict is not technically optional, but some tests in test-general
|
||||
* don't bother with it in cases where they know it's not needed.
|
||||
*/
|
||||
|
|
@ -813,19 +818,49 @@ _nm_setting_new_from_dbus (GType setting_type,
|
|||
*/
|
||||
setting = (NMSetting *) g_object_new (setting_type, NULL);
|
||||
|
||||
if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) {
|
||||
GVariantIter iter;
|
||||
GVariant *entry, *entry_key;
|
||||
char *key;
|
||||
|
||||
keys = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
|
||||
|
||||
g_variant_iter_init (&iter, setting_dict);
|
||||
while ((entry = g_variant_iter_next_value (&iter))) {
|
||||
entry_key = g_variant_get_child_value (entry, 0);
|
||||
key = g_strdup (g_variant_get_string (entry_key, NULL));
|
||||
g_variant_unref (entry_key);
|
||||
g_variant_unref (entry);
|
||||
|
||||
if (!nm_g_hash_table_add (keys, key)) {
|
||||
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_SETTING,
|
||||
_("duplicate property"));
|
||||
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), key);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
properties = nm_setting_class_get_properties (NM_SETTING_GET_CLASS (setting), &n_properties);
|
||||
for (i = 0; i < n_properties; i++) {
|
||||
const NMSettingProperty *property = &properties[i];
|
||||
GVariant *value;
|
||||
gs_unref_variant GVariant *value = NULL;
|
||||
gs_free_error GError *local = NULL;
|
||||
|
||||
if (property->param_spec && !(property->param_spec->flags & G_PARAM_WRITABLE))
|
||||
continue;
|
||||
|
||||
value = g_variant_lookup_value (setting_dict, property->name, NULL);
|
||||
|
||||
if (value && keys)
|
||||
g_hash_table_remove (keys, property->name);
|
||||
|
||||
if (value && property->set_func) {
|
||||
|
||||
if (!g_variant_type_equal (g_variant_get_type (value), property->dbus_type)) {
|
||||
property_type_error:
|
||||
/* 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 ?
|
||||
|
|
@ -834,36 +869,83 @@ _nm_setting_new_from_dbus (GType setting_type,
|
|||
g_type_name (property->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_variant_unref (value);
|
||||
g_object_unref (setting);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
property->set_func (setting,
|
||||
connection_dict,
|
||||
property->name,
|
||||
value);
|
||||
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) {
|
||||
property->not_set_func (setting,
|
||||
connection_dict,
|
||||
property->name);
|
||||
if (!property->not_set_func (setting,
|
||||
connection_dict,
|
||||
property->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->name);
|
||||
return NULL;
|
||||
}
|
||||
} else if (value && property->param_spec) {
|
||||
GValue object_value = { 0, };
|
||||
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))
|
||||
goto property_type_error;
|
||||
if (!set_property_from_dbus (property, 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)",
|
||||
g_variant_get_type_string (value));
|
||||
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), property->name);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
g_object_set_property (G_OBJECT (setting), property->param_spec->name, &object_value);
|
||||
g_value_unset (&object_value);
|
||||
if (!nm_g_object_set_property (G_OBJECT (setting), property->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);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (value)
|
||||
g_variant_unref (value);
|
||||
}
|
||||
|
||||
return setting;
|
||||
if ( NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)
|
||||
&& g_hash_table_size (keys) > 0) {
|
||||
GHashTableIter iter;
|
||||
const char *key;
|
||||
|
||||
g_hash_table_iter_init (&iter, keys);
|
||||
if (g_hash_table_iter_next (&iter, (gpointer *) &key, NULL)) {
|
||||
g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
||||
_("unknown property"));
|
||||
g_prefix_error (error, "%s.%s: ", nm_setting_get_name (setting), key);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return nm_unauto (&setting);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1025,7 +1025,7 @@ test_setting_new_from_dbus (void)
|
|||
dict = _nm_setting_to_dbus (NM_SETTING (s_wsec), NULL, NM_CONNECTION_SERIALIZE_ALL);
|
||||
g_object_unref (s_wsec);
|
||||
|
||||
s_wsec = (NMSettingWirelessSecurity *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_WIRELESS_SECURITY, dict, NULL, NULL);
|
||||
s_wsec = (NMSettingWirelessSecurity *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_WIRELESS_SECURITY, dict, NULL, NM_SETTING_PARSE_FLAGS_NONE, NULL);
|
||||
g_variant_unref (dict);
|
||||
|
||||
g_assert (s_wsec);
|
||||
|
|
@ -1054,7 +1054,7 @@ test_setting_new_from_dbus_transform (void)
|
|||
dbus_mac_address, ETH_ALEN, 1));
|
||||
dict = g_variant_builder_end (&builder);
|
||||
|
||||
s_wired = _nm_setting_new_from_dbus (NM_TYPE_SETTING_WIRED, dict, NULL, &error);
|
||||
s_wired = _nm_setting_new_from_dbus (NM_TYPE_SETTING_WIRED, dict, NULL, NM_SETTING_PARSE_FLAGS_NONE, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_assert_cmpstr (nm_setting_wired_get_mac_address (NM_SETTING_WIRED (s_wired)), ==, test_mac_address);
|
||||
|
|
@ -1080,7 +1080,7 @@ test_setting_new_from_dbus_enum (void)
|
|||
g_variant_new_int32 (NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR));
|
||||
dict = g_variant_builder_end (&builder);
|
||||
|
||||
s_ip6 = (NMSettingIP6Config *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_IP6_CONFIG, dict, NULL, &error);
|
||||
s_ip6 = (NMSettingIP6Config *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_IP6_CONFIG, dict, NULL, NM_SETTING_PARSE_FLAGS_NONE, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_assert_cmpint (nm_setting_ip6_config_get_ip6_privacy (s_ip6), ==, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR);
|
||||
|
|
@ -1099,7 +1099,7 @@ test_setting_new_from_dbus_enum (void)
|
|||
NM_SETTING_SECRET_FLAG_NOT_SAVED));
|
||||
dict = g_variant_builder_end (&builder);
|
||||
|
||||
s_wsec = (NMSettingWirelessSecurity *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_WIRELESS_SECURITY, dict, NULL, &error);
|
||||
s_wsec = (NMSettingWirelessSecurity *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_WIRELESS_SECURITY, dict, NULL, NM_SETTING_PARSE_FLAGS_NONE, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_assert_cmpint (nm_setting_wireless_security_get_wep_key_type (s_wsec), ==, NM_WEP_KEY_TYPE_KEY);
|
||||
|
|
@ -1116,7 +1116,7 @@ test_setting_new_from_dbus_enum (void)
|
|||
g_variant_new_byte ('E'));
|
||||
dict = g_variant_builder_end (&builder);
|
||||
|
||||
s_serial = (NMSettingSerial *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_SERIAL, dict, NULL, &error);
|
||||
s_serial = (NMSettingSerial *) _nm_setting_new_from_dbus (NM_TYPE_SETTING_SERIAL, dict, NULL, NM_SETTING_PARSE_FLAGS_NONE, &error);
|
||||
g_assert_no_error (error);
|
||||
|
||||
g_assert_cmpint (nm_setting_serial_get_parity (s_serial), ==, NM_SETTING_SERIAL_PARITY_EVEN);
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue