all: merge branch 'th/invalid-connections-bgo760907'
authorThomas Haller <thaller@redhat.com>
Tue, 29 Mar 2016 09:56:37 +0000 (11:56 +0200)
committerThomas Haller <thaller@redhat.com>
Tue, 29 Mar 2016 09:57:49 +0000 (11:57 +0200)
https://bugzilla.gnome.org/show_bug.cgi?id=760907

42 files changed:
libnm-core/Makefile.libnm-core
libnm-core/nm-connection.c
libnm-core/nm-core-internal.h
libnm-core/nm-setting-connection.c
libnm-core/nm-setting-ip-config.c
libnm-core/nm-setting-ip4-config.c
libnm-core/nm-setting-ip6-config.c
libnm-core/nm-setting-private.h
libnm-core/nm-setting-vlan.c
libnm-core/nm-setting.c
libnm-core/nm-simple-connection.c
libnm-core/nm-utils.c
libnm-core/tests/test-general.c
libnm-glib/nm-remote-connection.c
libnm-glib/nm-secret-agent.c
libnm-glib/nm-vpn-plugin.c
libnm-glib/tests/test-nm-client.c
libnm-util/Makefile.am
libnm-util/libnm-util.ver
libnm-util/nm-connection.c
libnm-util/nm-setting-private.h
libnm-util/nm-setting.c
libnm/nm-client.c
libnm/nm-device.c
libnm/nm-remote-connection.c
libnm/nm-secret-agent-old.c
libnm/nm-vpn-plugin-old.c
libnm/nm-vpn-service-plugin.c
libnm/tests/test-nm-client.c
po/POTFILES.in
shared/Makefile.am
shared/nm-default.h
shared/nm-macros-internal.h
shared/nm-shared-utils.c [new file with mode: 0644]
shared/nm-shared-utils.h [new file with mode: 0644]
shared/nm-test-utils.h
src/devices/nm-device.c
src/nm-core-utils.c
src/nm-core-utils.h
src/nm-manager.c
src/settings/nm-settings-connection.c
src/settings/nm-settings.c

index fe8cc8a..0038ce2 100644 (file)
@@ -52,6 +52,7 @@ libnm_core_headers =                          \
        $(core)/nm-vpn-plugin-info.h
 
 libnm_core_private_headers =                   \
+       $(top_builddir)/shared/nm-shared-utils.h \
        $(core)/crypto.h                        \
        $(core)/nm-connection-private.h         \
        $(core)/nm-core-internal.h              \
@@ -63,6 +64,7 @@ libnm_core_private_headers =                  \
        $(core)/nm-utils-private.h
 
 libnm_core_sources =                           \
+       $(top_builddir)/shared/nm-shared-utils.c \
        $(core_build)/nm-core-enum-types.c      \
        $(core)/crypto.c                        \
        $(core)/nm-connection.c                 \
index 04e601c..c03e626 100644 (file)
@@ -233,9 +233,10 @@ validate_permissions_type (GVariant *variant, GError **error)
 }
 
 /**
- * nm_connection_replace_settings:
+ * _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
@@ -244,49 +245,82 @@ validate_permissions_type (GVariant *variant, GError **error)
  *
  * Returns: %TRUE if connection was updated, %FALSE if @new_settings could not
  *   be deserialized (in which case @connection will be unchanged).
+ *   Only exception is the NM_SETTING_PARSE_FLAGS_NORMALIZE flag: if normalization
+ *   fails, the input @connection is already modified and the original settings
+ *   are lost.
  **/
 gboolean
-nm_connection_replace_settings (NMConnection *connection,
-                                GVariant *new_settings,
-                                GError **error)
+_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;
+       gboolean changed, success;
 
        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 (!validate_permissions_type (new_settings, error))
+       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_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);
+               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;
                }
@@ -300,14 +334,50 @@ nm_connection_replace_settings (NMConnection *connection,
        } 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 verification/normalization fails, the original connection
+        * is already lost. From an API point of view, it would be nicer
+        * not to touch the input argument if we fail at the end.
+        * However, that would require creating a temporary connection
+        * to validate it first. As none of the caller cares about the
+        * state of the @connection when normalization fails, just do it
+        * this way. */
+       if (NM_FLAGS_HAS (parse_flags, NM_SETTING_PARSE_FLAGS_NORMALIZE))
+               success = nm_connection_normalize (connection, NULL, NULL, error);
+       else
+               success = TRUE;
+
        if (changed)
                g_signal_emit (connection, signals[CHANGED], 0);
-       return TRUE;
+       return success;
+}
+
+/**
+ * nm_connection_replace_settings:
+ * @connection: a #NMConnection
+ * @new_settings: a #GVariant of type %NM_VARIANT_TYPE_CONNECTION, with the new settings
+ * @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,
+                                GError **error)
+{
+       return _nm_connection_replace_settings (connection, new_settings, NM_SETTING_PARSE_FLAGS_NONE, error);
 }
 
 /**
index 3e1236b..9512ee5 100644 (file)
         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_NORMALIZE                = 1LL << 2,
+
+       _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);
+
+NMConnection *_nm_simple_connection_new_from_dbus (GVariant      *dict,
+                                                   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);
@@ -179,8 +198,6 @@ GByteArray *nm_utils_rsa_key_encrypt (const guint8 *data,
                                       char **out_password,
                                       GError **error);
 
-gint64 _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback);
-
 gulong _nm_dbus_signal_connect_data (GDBusProxy *proxy,
                                      const char *signal_name,
                                      const GVariantType *signature,
index 44237d9..e1cd913 100644 (file)
@@ -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
index d76179c..a69045b 100644 (file)
@@ -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
index b0308e7..9b479a0 100644 (file)
@@ -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;
 }
 
 
index f2d8508..bab8c53 100644 (file)
@@ -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
index cb7ca52..6560c4a 100644 (file)
@@ -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,
index 39587d5..827a47a 100644 (file)
@@ -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 *
index fec645b..0c41bd8 100644 (file)
@@ -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);
+       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 setting;
+       return nm_unauto (&setting);
 }
 
 /**
index 1036c8e..1170066 100644 (file)
@@ -51,7 +51,7 @@ nm_simple_connection_new (void)
 }
 
 /**
- * nm_simple_connection_new_from_dbus:
+ * _nm_simple_connection_new_from_dbus:
  * @dict: a #GVariant of type %NM_VARIANT_TYPE_CONNECTION describing the connection
  * @error: on unsuccessful return, an error
  *
@@ -60,24 +60,46 @@ nm_simple_connection_new (void)
  * hash table.
  *
  * Returns: (transfer full): the new #NMSimpleConnection object, populated with
- * settings created from the values in the hash table, or %NULL if the
- * connection failed to validate
+ * settings created from the values in the hash table, or %NULL if there was
+ * an error.
  **/
 NMConnection *
-nm_simple_connection_new_from_dbus (GVariant *dict, GError **error)
+_nm_simple_connection_new_from_dbus (GVariant *dict, NMSettingParseFlags parse_flags, GError **error)
 {
        NMConnection *connection;
 
        g_return_val_if_fail (dict != NULL, NULL);
        g_return_val_if_fail (g_variant_is_of_type (dict, NM_VARIANT_TYPE_CONNECTION), NULL);
+       g_return_val_if_fail (!NM_FLAGS_ANY (parse_flags, ~NM_SETTING_PARSE_FLAGS_ALL), NULL);
+       g_return_val_if_fail (!NM_FLAGS_ALL (parse_flags, NM_SETTING_PARSE_FLAGS_STRICT | NM_SETTING_PARSE_FLAGS_BEST_EFFORT), NULL);
 
        connection = nm_simple_connection_new ();
-       if (   !nm_connection_replace_settings (connection, dict, error)
-           || !nm_connection_normalize (connection, NULL, NULL, error))
+       if (!_nm_connection_replace_settings (connection, dict, parse_flags, error))
                g_clear_object (&connection);
        return connection;
 }
 
+/**
+ * nm_simple_connection_new_from_dbus:
+ * @dict: a #GVariant of type %NM_VARIANT_TYPE_CONNECTION describing the connection
+ * @error: on unsuccessful return, an error
+ *
+ * Creates a new #NMSimpleConnection from a hash table describing the
+ * connection and normalize the connection.  See nm_connection_to_dbus() for a
+ * description of the expected hash table.
+ *
+ * Returns: (transfer full): the new #NMSimpleConnection object, populated with
+ * settings created from the values in the hash table, or %NULL if the
+ * connection failed to normalize.
+ **/
+NMConnection *
+nm_simple_connection_new_from_dbus (GVariant *dict, GError **error)
+{
+       return _nm_simple_connection_new_from_dbus (dict,
+                                                   NM_SETTING_PARSE_FLAGS_NORMALIZE,
+                                                   error);
+}
+
 /**
  * nm_simple_connection_new_clone:
  * @connection: the #NMConnection to clone
index 10d54fa..a846708 100644 (file)
@@ -3789,81 +3789,6 @@ _nm_utils_strstrdictkey_create (const char *v1, const char *v2)
        return k;
 }
 
-/**********************************************************************************************/
-
-/* _nm_utils_ascii_str_to_int64:
- *
- * A wrapper for g_ascii_strtoll, that checks whether the whole string
- * can be successfully converted to a number and is within a given
- * range. On any error, @fallback will be returned and %errno will be set
- * to a non-zero value. On success, %errno will be set to zero, check %errno
- * for errors. Any trailing or leading (ascii) white space is ignored and the
- * functions is locale independent.
- *
- * The function is guaranteed to return a value between @min and @max
- * (inclusive) or @fallback. Also, the parsing is rather strict, it does
- * not allow for any unrecognized characters, except leading and trailing
- * white space.
- **/
-gint64
-_nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback)
-{
-       gint64 v;
-       size_t len;
-       char buf[64], *s, *str_free = NULL;
-
-       if (str) {
-               while (g_ascii_isspace (str[0]))
-                       str++;
-       }
-       if (!str || !str[0]) {
-               errno = EINVAL;
-               return fallback;
-       }
-
-       len = strlen (str);
-       if (g_ascii_isspace (str[--len])) {
-               /* backward search the first non-ws character.
-                * We already know that str[0] is non-ws. */
-               while (g_ascii_isspace (str[--len]))
-                       ;
-
-               /* str[len] is now the last non-ws character... */
-               len++;
-
-               if (len >= sizeof (buf))
-                       s = str_free = g_malloc (len + 1);
-               else
-                       s = buf;
-
-               memcpy (s, str, len);
-               s[len] = 0;
-
-               nm_assert (len > 0 && len < strlen (str) && len == strlen (s));
-               nm_assert (!g_ascii_isspace (str[len-1]) && g_ascii_isspace (str[len]));
-               nm_assert (strncmp (str, s, len) == 0);
-
-               str = s;
-       }
-
-       errno = 0;
-       v = g_ascii_strtoll (str, &s, base);
-
-       if (errno != 0)
-               v = fallback;
-       else if (s[0] != 0) {
-               errno = EINVAL;
-               v = fallback;
-       } else if (v > max || v < min) {
-               errno = ERANGE;
-               v = fallback;
-       }
-
-       if (G_UNLIKELY (str_free))
-               g_free (str_free);
-       return v;
-}
-
 static gboolean
 validate_dns_option (const char *name, gboolean numeric, gboolean ipv6,
                      const NMUtilsDNSOptionDesc *option_descs)
index 82af414..dcbcb88 100644 (file)
@@ -74,6 +74,12 @@ G_STATIC_ASSERT (sizeof (bool) <= sizeof (int));
 
 /*****************************************************************************/
 
+static NMConnection *
+_connection_new_from_dbus (GVariant *dict, GError **error)
+{
+       return _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_NORMALIZE, error);
+}
+
 static void
 vpn_check_func (const char *key, const char *value, gpointer user_data)
 {
@@ -450,7 +456,7 @@ test_setting_ip4_config_labels (void)
                              NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP4_CONFIG_SETTING_NAME,
                                                           "address-data");
                              );
-       conn = nm_simple_connection_new_from_dbus (dict, &error);
+       conn = _connection_new_from_dbus (dict, &error);
        g_assert_no_error (error);
        g_variant_unref (dict);
 
@@ -473,7 +479,7 @@ test_setting_ip4_config_labels (void)
                              NMTST_VARIANT_DROP_PROPERTY (NM_SETTING_IP4_CONFIG_SETTING_NAME,
                                                           "address-labels");
                              );
-       conn = nm_simple_connection_new_from_dbus (dict2, &error);
+       conn = _connection_new_from_dbus (dict2, &error);
        g_assert_no_error (error);
        g_variant_unref (dict2);
 
@@ -603,7 +609,7 @@ test_setting_ip4_config_address_data (void)
        g_object_unref (conn);
 
        /* When we reserialize that dictionary as a client, 'address-data' will be preferred. */
-       conn = nm_simple_connection_new_from_dbus (dict, &error);
+       conn = _connection_new_from_dbus (dict, &error);
        g_assert_no_error (error);
 
        s_ip4 = nm_connection_get_setting_ip4_config (conn);
@@ -619,7 +625,7 @@ test_setting_ip4_config_address_data (void)
 
        /* But on the server side, 'addresses' will have precedence. */
        _nm_utils_is_manager_process = TRUE;
-       conn = nm_simple_connection_new_from_dbus (dict, &error);
+       conn = _connection_new_from_dbus (dict, &error);
        _nm_utils_is_manager_process = FALSE;
        g_assert_no_error (error);
        g_variant_unref (dict);
@@ -1025,7 +1031,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 +1060,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 +1086,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 +1105,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 +1122,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);
@@ -1188,7 +1194,7 @@ test_setting_new_from_dbus_bad (void)
        g_object_unref (conn);
 
        /* sanity-check */
-       conn = nm_simple_connection_new_from_dbus (orig_dict, &error);
+       conn = _connection_new_from_dbus (orig_dict, &error);
        g_assert_no_error (error);
        g_assert (conn);
        g_object_unref (conn);
@@ -1201,7 +1207,7 @@ test_setting_new_from_dbus_bad (void)
                                                             NM_SETTING_WIRELESS_RATE,
                                                             "i", 10);
                              );
-       conn = nm_simple_connection_new_from_dbus (dict, &error);
+       conn = _connection_new_from_dbus (dict, &error);
        g_assert (conn);
        g_assert_no_error (error);
        setting = nm_connection_get_setting (conn, NM_TYPE_SETTING_WIRELESS);
@@ -1216,7 +1222,7 @@ test_setting_new_from_dbus_bad (void)
                                                             NM_SETTING_IP6_CONFIG_IP6_PRIVACY,
                                                             "i", NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR);
                              );
-       conn = nm_simple_connection_new_from_dbus (dict, &error);
+       conn = _connection_new_from_dbus (dict, &error);
        g_assert (conn);
        g_assert_no_error (error);
        setting = nm_connection_get_setting (conn, NM_TYPE_SETTING_IP6_CONFIG);
@@ -1233,7 +1239,7 @@ test_setting_new_from_dbus_bad (void)
                                                             NM_SETTING_WIRELESS_RATE,
                                                             "s", "ten");
                              );
-       conn = nm_simple_connection_new_from_dbus (dict, &error);
+       conn = _connection_new_from_dbus (dict, &error);
        g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
        g_assert (g_str_has_prefix (error->message, "802-11-wireless.rate:"));
        g_clear_error (&error);
@@ -1245,7 +1251,7 @@ test_setting_new_from_dbus_bad (void)
                                                             NM_SETTING_WIRELESS_MODE,
                                                             "b", FALSE);
                              );
-       conn = nm_simple_connection_new_from_dbus (dict, &error);
+       conn = _connection_new_from_dbus (dict, &error);
        g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
        g_assert (g_str_has_prefix (error->message, "802-11-wireless.mode:"));
        g_clear_error (&error);
@@ -1257,7 +1263,7 @@ test_setting_new_from_dbus_bad (void)
                                                             NM_SETTING_WIRELESS_SSID,
                                                             "s", "fred");
                              );
-       conn = nm_simple_connection_new_from_dbus (dict, &error);
+       conn = _connection_new_from_dbus (dict, &error);
        g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
        g_assert (g_str_has_prefix (error->message, "802-11-wireless.ssid:"));
        g_clear_error (&error);
@@ -1269,7 +1275,7 @@ test_setting_new_from_dbus_bad (void)
                                                             NM_SETTING_WIRELESS_BSSID,
                                                             "i", 42);
                              );
-       conn = nm_simple_connection_new_from_dbus (dict, &error);
+       conn = _connection_new_from_dbus (dict, &error);
        g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
        g_assert (g_str_has_prefix (error->message, "802-11-wireless.bssid:"));
        g_clear_error (&error);
@@ -1281,7 +1287,7 @@ test_setting_new_from_dbus_bad (void)
                                                             NM_SETTING_IP6_CONFIG_IP6_PRIVACY,
                                                             "s", "private");
                              );
-       conn = nm_simple_connection_new_from_dbus (dict, &error);
+       conn = _connection_new_from_dbus (dict, &error);
        g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
        g_assert (g_str_has_prefix (error->message, "ipv6.ip6-privacy:"));
        g_clear_error (&error);
@@ -1293,7 +1299,7 @@ test_setting_new_from_dbus_bad (void)
                                                             NM_SETTING_IP_CONFIG_ADDRESSES,
                                                             "s", "1234::5678");
                              );
-       conn = nm_simple_connection_new_from_dbus (dict, &error);
+       conn = _connection_new_from_dbus (dict, &error);
        g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
        g_assert (g_str_has_prefix (error->message, "ipv6.addresses:"));
        g_clear_error (&error);
@@ -1561,7 +1567,7 @@ test_connection_new_from_dbus (void)
        g_assert (new_settings);
 
        /* Replace settings and test */
-       connection = nm_simple_connection_new_from_dbus (new_settings, &error);
+       connection = _connection_new_from_dbus (new_settings, &error);
        g_assert_no_error (error);
        g_assert (connection);
 
@@ -3241,7 +3247,7 @@ test_connection_normalize_virtual_iface_name (void)
                                                             ":::this-is-not-a-valid-interface-name:::");
                              );
 
-       con = nm_simple_connection_new_from_dbus (connection_dict, &error);
+       con = _connection_new_from_dbus (connection_dict, &error);
        g_assert_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY);
        g_clear_error (&error);
 
@@ -3253,7 +3259,7 @@ test_connection_normalize_virtual_iface_name (void)
                                                             IFACE_VIRT);
                              );
 
-       con = nm_simple_connection_new_from_dbus (connection_dict, &error);
+       con = _connection_new_from_dbus (connection_dict, &error);
        g_assert_no_error (error);
 
        g_assert_cmpstr (nm_connection_get_interface_name (con), ==, IFACE_NAME);
@@ -3269,7 +3275,7 @@ test_connection_normalize_virtual_iface_name (void)
                                                           NM_SETTING_CONNECTION_INTERFACE_NAME);
                              );
 
-       con = nm_simple_connection_new_from_dbus (connection_dict, &error);
+       con = _connection_new_from_dbus (connection_dict, &error);
        g_assert_no_error (error);
 
        g_assert_cmpstr (nm_connection_get_interface_name (con), ==, IFACE_VIRT);
@@ -3783,7 +3789,7 @@ test_setting_ip4_gateway (void)
                                                           "address-data");
                              );
 
-       conn = nm_simple_connection_new_from_dbus (conn_dict, &error);
+       conn = _connection_new_from_dbus (conn_dict, &error);
        g_assert_no_error (error);
 
        s_ip4 = (NMSettingIPConfig *) nm_connection_get_setting_ip4_config (conn);
@@ -3805,7 +3811,7 @@ test_setting_ip4_gateway (void)
                                                             "addresses", "aau", &addrs_builder);
                              );
 
-       conn = nm_simple_connection_new_from_dbus (conn_dict, &error);
+       conn = _connection_new_from_dbus (conn_dict, &error);
        g_assert_no_error (error);
        g_variant_unref (conn_dict);
 
@@ -3890,7 +3896,7 @@ test_setting_ip6_gateway (void)
                                                           "address-data");
                              );
 
-       conn = nm_simple_connection_new_from_dbus (conn_dict, &error);
+       conn = _connection_new_from_dbus (conn_dict, &error);
        g_assert_no_error (error);
 
        s_ip6 = (NMSettingIPConfig *) nm_connection_get_setting_ip6_config (conn);
@@ -3918,7 +3924,7 @@ test_setting_ip6_gateway (void)
                                                             "addresses", "a(ayuay)", &addrs_builder);
                              );
 
-       conn = nm_simple_connection_new_from_dbus (conn_dict, &error);
+       conn = _connection_new_from_dbus (conn_dict, &error);
        g_assert_no_error (error);
        g_variant_unref (conn_dict);
 
index 132032f..a4dc638 100644 (file)
@@ -31,6 +31,7 @@
 #include "nm-object-private.h"
 #include "nm-dbus-glib-types.h"
 #include "nm-dbus-helpers-private.h"
+#include "nm-setting-private.h"
 
 #define NM_REMOTE_CONNECTION_BUS "bus"
 #define NM_REMOTE_CONNECTION_DBUS_CONNECTION "dbus-connection"
@@ -446,24 +447,6 @@ nm_remote_connection_get_unsaved (NMRemoteConnection *connection)
 
 /****************************************************************/
 
-static void
-replace_settings (NMRemoteConnection *self, GHashTable *new_settings)
-{
-       GError *error = NULL;
-
-       if (nm_connection_replace_settings (NM_CONNECTION (self), new_settings, &error))
-               g_signal_emit (self, signals[UPDATED], 0, new_settings);
-       else {
-               g_warning ("%s: error updating connection %s settings: %s",
-                          __func__,
-                          nm_connection_get_path (NM_CONNECTION (self)),
-                          error->message);
-               g_clear_error (&error);
-
-               g_signal_emit (self, signals[REMOVED], 0);
-       }
-}
-
 static void
 updated_get_settings_cb (DBusGProxy *proxy,
                          DBusGProxyCall *call,
@@ -488,7 +471,7 @@ updated_get_settings_cb (DBusGProxy *proxy,
                 * object.
                 */
                hash = g_hash_table_new (g_str_hash, g_str_equal);
-               nm_connection_replace_settings (NM_CONNECTION (self), hash, NULL);
+               _nm_connection_replace_settings (NM_CONNECTION (self), hash);
                g_hash_table_destroy (hash);
 
                priv->visible = FALSE;
@@ -497,7 +480,8 @@ updated_get_settings_cb (DBusGProxy *proxy,
                gs_unref_object NMConnection *self_alive = NULL;
 
                self_alive = g_object_ref (self);
-               replace_settings (self, new_settings);
+               _nm_connection_replace_settings (NM_CONNECTION (self), new_settings);
+               g_signal_emit (self, signals[UPDATED], 0, new_settings);
                g_hash_table_destroy (new_settings);
 
                /* Settings service will handle announcing the connection to clients */
@@ -628,7 +612,8 @@ init_sync (GInitable *initable, GCancellable *cancellable, GError **error)
                return FALSE;
        priv->visible = TRUE;
        self_alive = g_object_ref (initable);
-       replace_settings (NM_REMOTE_CONNECTION (initable), hash);
+       _nm_connection_replace_settings (NM_CONNECTION (initable), hash);
+       g_signal_emit (initable, signals[UPDATED], 0, hash);
        g_hash_table_destroy (hash);
 
        /* Get properties */
@@ -703,7 +688,8 @@ init_get_settings_cb (DBusGProxy *proxy,
 
        priv->visible = TRUE;
        self_alive = g_object_ref (init_data->connection);
-       replace_settings (init_data->connection, settings);
+       _nm_connection_replace_settings (NM_CONNECTION (init_data->connection), settings);
+       g_signal_emit (init_data->connection, signals[UPDATED], 0, settings);
        g_hash_table_destroy (settings);
 
        /* Grab properties */
index 0a86245..0329046 100644 (file)
@@ -27,6 +27,7 @@
 #include "nm-secret-agent.h"
 #include "nm-glib-enum-types.h"
 #include "nm-dbus-helpers-private.h"
+#include "nm-setting-private.h"
 
 static void impl_secret_agent_get_secrets (NMSecretAgent *self,
                                            GHashTable *connection_hash,
@@ -302,7 +303,8 @@ verify_request (NMSecretAgent *self,
                 GError **error)
 {
        NMConnection *connection = NULL;
-       GError *local = NULL;
+
+       g_return_val_if_fail (out_connection, FALSE);
 
        if (!verify_sender (self, context, error))
                return FALSE;
@@ -321,21 +323,11 @@ verify_request (NMSecretAgent *self,
        }
 
        /* Make sure the given connection is valid */
-       g_assert (out_connection);
-       connection = nm_connection_new_from_hash (connection_hash, &local);
-       if (connection) {
-               nm_connection_set_path (connection, connection_path);
-               *out_connection = connection;
-       } else {
-               g_set_error (error,
-                            NM_SECRET_AGENT_ERROR,
-                            NM_SECRET_AGENT_ERROR_INVALID_CONNECTION,
-                            "Invalid connection: %s",
-                            local->message);
-               g_clear_error (&local);
-       }
+       connection = _nm_connection_new_from_hash (connection_hash);
+       nm_connection_set_path (connection, connection_path);
+       *out_connection = connection;
 
-       return !!connection;
+       return TRUE;
 }
 
 static void
index d117e53..2af9deb 100644 (file)
@@ -29,6 +29,7 @@
 #include "nm-utils.h"
 #include "nm-connection.h"
 #include "nm-dbus-glib-types.h"
+#include "nm-setting-private.h"
 
 static gboolean impl_vpn_plugin_connect    (NMVPNPlugin *plugin,
                                             GHashTable *connection,
@@ -452,13 +453,7 @@ _connect_generic (NMVPNPlugin *plugin,
                return FALSE;
        }
 
-       connection = nm_connection_new_from_hash (properties, &local);
-       if (!connection) {
-               g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
-                            "Invalid connection: %s", local->message);
-               g_clear_error (&local);
-               return FALSE;
-       }
+       connection = _nm_connection_new_from_hash (properties);
 
        priv->interactive = FALSE;
        if (details && !vpn_class->connect_interactive) {
@@ -526,22 +521,11 @@ impl_vpn_plugin_need_secrets (NMVPNPlugin *plugin,
        char *sn = NULL;
        GError *ns_err = NULL;
        gboolean needed = FALSE;
-       GError *cnfh_err = NULL;
 
        g_return_val_if_fail (NM_IS_VPN_PLUGIN (plugin), FALSE);
        g_return_val_if_fail (properties != NULL, FALSE);
 
-       connection = nm_connection_new_from_hash (properties, &cnfh_err);
-       if (!connection) {
-               g_set_error (err,
-                            NM_VPN_PLUGIN_ERROR,
-                            NM_VPN_PLUGIN_ERROR_CONNECTION_INVALID,
-                            "The connection was invalid: '%s' / '%s' invalid.",
-                            g_type_name (nm_connection_lookup_setting_type_by_quark (cnfh_err->domain)),
-                            cnfh_err->message);
-               g_error_free (cnfh_err);
-               return FALSE;
-       }
+       connection = _nm_connection_new_from_hash (properties);
 
        if (!NM_VPN_PLUGIN_GET_CLASS (plugin)->need_secrets) {
                *setting_name = "";
@@ -581,7 +565,6 @@ impl_vpn_plugin_new_secrets (NMVPNPlugin *plugin,
 {
        NMVPNPluginPrivate *priv = NM_VPN_PLUGIN_GET_PRIVATE (plugin);
        NMConnection *connection;
-       GError *local = NULL;
        gboolean success;
 
        if (priv->state != NM_VPN_SERVICE_STATE_STARTING) {
@@ -591,14 +574,7 @@ impl_vpn_plugin_new_secrets (NMVPNPlugin *plugin,
                return FALSE;
        }
 
-       connection = nm_connection_new_from_hash (properties, &local);
-       if (!connection) {
-               g_set_error (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_BAD_ARGUMENTS,
-                            "Invalid connection: %s",
-                            local->message);
-               g_clear_error (&local);
-               return FALSE;
-       }
+       connection = _nm_connection_new_from_hash (properties);
 
        if (!NM_VPN_PLUGIN_GET_CLASS (plugin)->new_secrets) {
                g_set_error_literal (error, NM_VPN_PLUGIN_ERROR, NM_VPN_PLUGIN_ERROR_INTERACTIVE_NOT_SUPPORTED,
index da2e39e..0da93c3 100644 (file)
@@ -955,12 +955,8 @@ test_connection_invalid (void)
 
        settings = nmtstc_nm_remote_settings_new ();
 
-       g_test_expect_message ("libnm-glib", G_LOG_LEVEL_WARNING, "*replace_settings: error updating connection*");
-
        nmtst_main_loop_run (loop, 100);
 
-       g_test_assert_expected_messages ();
-
        _slist_to_array (&connections, nm_remote_settings_list_connections (settings));
 
        g_assert_cmpint (connections->len, ==, 2);
@@ -991,12 +987,8 @@ test_connection_invalid (void)
                                       FALSE,
                                       &path2);
 
-       g_test_expect_message ("libnm-glib", G_LOG_LEVEL_WARNING, "*replace_settings: error updating connection*");
-
        nmtst_main_loop_run (loop, 100);
 
-       g_test_assert_expected_messages ();
-
        _slist_to_array (&connections, nm_remote_settings_list_connections (settings));
 
        g_assert_cmpint (connections->len, ==, 3);
@@ -1027,15 +1019,11 @@ test_connection_invalid (void)
                                          connection,
                                          FALSE);
 
-       g_test_expect_message ("libnm-glib", G_LOG_LEVEL_WARNING, "*replace_settings: error updating connection*");
-
        nmtst_main_loop_run (loop, 100);
 
-       g_test_assert_expected_messages ();
-
        _slist_to_array (&connections, nm_remote_settings_list_connections (settings));
 
-       g_assert_cmpint (connections->len, ==, 2);
+       g_assert_cmpint (connections->len, ==, 3);
        n_found = nmtst_find_all_indexes (connections->pdata,
                                          connections->len,
                                          (gpointer *) ((const char *[]) { path0, path1, path2 }),
@@ -1043,12 +1031,13 @@ test_connection_invalid (void)
                                          _test_connection_invalid_find_connections,
                                          NULL,
                                          idx);
-       g_assert_cmpint (n_found, ==, 2);
+       g_assert_cmpint (n_found, ==, 3);
        ASSERT_IDX (0);
        ASSERT_IDX (1);
-       g_assert_cmpint (idx[2], ==, -1);
+       ASSERT_IDX (2);
        nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[0]]);
        nmtst_assert_connection_unnormalizable (connections->pdata[idx[1]], 0, 0);
+       nmtst_assert_connection_unnormalizable (connections->pdata[idx[2]], 0, 0);
 
        /**************************************************************************
         * Modify the invalid connection again. Note that the connection stays
@@ -1073,7 +1062,7 @@ test_connection_invalid (void)
 
        _slist_to_array (&connections, nm_remote_settings_list_connections (settings));
 
-       g_assert_cmpint (connections->len, ==, 2);
+       g_assert_cmpint (connections->len, ==, 3);
        n_found = nmtst_find_all_indexes (connections->pdata,
                                          connections->len,
                                          (gpointer *) ((const char *[]) { path0, path1, path2 }),
@@ -1081,12 +1070,13 @@ test_connection_invalid (void)
                                          _test_connection_invalid_find_connections,
                                          NULL,
                                          idx);
-       g_assert_cmpint (n_found, ==, 2);
+       g_assert_cmpint (n_found, ==, 3);
        ASSERT_IDX (0);
        ASSERT_IDX (1);
-       g_assert_cmpint (idx[2], ==, -1);
+       ASSERT_IDX (2);
        nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[0]]);
        nmtst_assert_connection_unnormalizable (connections->pdata[idx[1]], 0, 0);
+       nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[2]]);
 
 
        /**************************************************************************
@@ -1111,7 +1101,7 @@ test_connection_invalid (void)
 
        _slist_to_array (&connections, nm_remote_settings_list_connections (settings));
 
-       g_assert_cmpint (connections->len, ==, 2);
+       g_assert_cmpint (connections->len, ==, 3);
        n_found = nmtst_find_all_indexes (connections->pdata,
                                          connections->len,
                                          (gpointer *) ((const char *[]) { path0, path1, path2 }),
@@ -1119,12 +1109,13 @@ test_connection_invalid (void)
                                          _test_connection_invalid_find_connections,
                                          NULL,
                                          idx);
-       g_assert_cmpint (n_found, ==, 2);
+       g_assert_cmpint (n_found, ==, 3);
        ASSERT_IDX (0);
        ASSERT_IDX (1);
-       g_assert_cmpint (idx[2], ==, -1);
+       ASSERT_IDX (2);
        nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[0]]);
        nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[1]]);
+       nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[2]]);
        g_assert_cmpstr ("test-connection-invalid-1x", ==, nm_connection_get_id (connections->pdata[idx[1]]));
 
 #undef ASSERT_IDX
index 6e63790..e9ccdae 100644 (file)
@@ -63,6 +63,7 @@ nodist_libnm_util_include_HEADERS = \
        nm-utils-enum-types.h
 
 libnm_util_la_private_headers = \
+       $(top_builddir)/shared/nm-shared-utils.h \
        crypto.h                        \
        nm-dbus-glib-types.h            \
        nm-gvaluearray-compat.h         \
@@ -71,6 +72,7 @@ libnm_util_la_private_headers = \
        nm-utils-private.h
 
 libnm_util_la_csources = \
+       $(top_builddir)/shared/nm-shared-utils.c \
        crypto.c                        \
        nm-connection.c                 \
        nm-param-spec-specialized.c     \
index 1ad853f..385cdb8 100644 (file)
@@ -1,5 +1,7 @@
 {
 global:
+       _nm_connection_new_from_hash;
+       _nm_connection_replace_settings;
        nm_connection_add_setting;
        nm_connection_clear_secrets;
        nm_connection_clear_secrets_with_flags;
index c440fb1..51c4802 100644 (file)
@@ -327,19 +327,30 @@ validate_permissions_type (GHashTable *hash, GError **error)
        return TRUE;
 }
 
-static gboolean
-hash_to_connection (NMConnection *connection, GHashTable *new, GError **error)
+/**
+ * _nm_connection_replace_settings:
+ * @connection: a #NMConnection
+ * @new_settings: (element-type utf8 GLib.HashTable): a #GHashTable of settings
+ **/
+void
+_nm_connection_replace_settings (NMConnection *connection,
+                                 GHashTable *new_settings)
 {
+       NMConnectionPrivate *priv = NM_CONNECTION_GET_PRIVATE (connection);
        GHashTableIter iter;
        const char *setting_name;
        GHashTable *setting_hash;
-       gboolean changed, valid;
-       NMConnectionPrivate *priv = NM_CONNECTION_GET_PRIVATE (connection);
+       gboolean changed;
+
+       g_return_if_fail (NM_IS_CONNECTION (connection));
+       g_return_if_fail (new_settings != NULL);
+
+       priv = NM_CONNECTION_GET_PRIVATE (connection);
 
        if ((changed = g_hash_table_size (priv->settings) > 0))
                g_hash_table_foreach_remove (priv->settings, _setting_release, connection);
 
-       g_hash_table_iter_init (&iter, new);
+       g_hash_table_iter_init (&iter, new_settings);
        while (g_hash_table_iter_next (&iter, (gpointer) &setting_name, (gpointer) &setting_hash)) {
                GType type = nm_connection_lookup_setting_type (setting_name);
 
@@ -353,10 +364,8 @@ hash_to_connection (NMConnection *connection, GHashTable *new, GError **error)
                }
        }
 
-       valid = nm_connection_verify (connection, error);
        if (changed)
                g_signal_emit (connection, signals[CHANGED], 0);
-       return valid;
 }
 
 /**
@@ -373,16 +382,15 @@ nm_connection_replace_settings (NMConnection *connection,
                                 GHashTable *new_settings,
                                 GError **error)
 {
-       gboolean valid = FALSE;
-
        g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
        g_return_val_if_fail (new_settings != NULL, FALSE);
-       if (error)
-               g_return_val_if_fail (*error == NULL, FALSE);
+       g_return_val_if_fail (!error || !*error, FALSE);
 
-       if (validate_permissions_type (new_settings, error))
-               valid = hash_to_connection (connection, new_settings, error);
-       return valid;
+       if (!validate_permissions_type (new_settings, error))
+               return FALSE;
+
+       _nm_connection_replace_settings (connection, new_settings);
+       return nm_connection_verify (connection, error);
 }
 
 /**
@@ -409,7 +417,8 @@ nm_connection_replace_settings_from_connection (NMConnection *connection,
        NMConnectionPrivate *priv;
        GHashTableIter iter;
        NMSetting *setting;
-       gboolean changed, valid;
+       gboolean changed = FALSE;
+       gboolean valid;
 
        g_return_val_if_fail (NM_IS_CONNECTION (connection), FALSE);
        g_return_val_if_fail (NM_IS_CONNECTION (new_connection), FALSE);
@@ -418,7 +427,7 @@ nm_connection_replace_settings_from_connection (NMConnection *connection,
        /* When 'connection' and 'new_connection' are the same object simply return
         * in order not to destroy 'connection' */
        if (connection == new_connection)
-               return TRUE;
+               goto out;
 
        /* No need to validate permissions like nm_connection_replace_settings()
         * since we're dealing with an NMConnection which has already done that.
@@ -435,6 +444,7 @@ nm_connection_replace_settings_from_connection (NMConnection *connection,
                changed = TRUE;
        }
 
+out:
        valid =  nm_connection_verify (connection, error);
        if (changed)
                g_signal_emit (connection, signals[CHANGED], 0);
@@ -1440,6 +1450,29 @@ nm_connection_new (void)
        return (NMConnection *) g_object_new (NM_TYPE_CONNECTION, NULL);
 }
 
+/**
+ * _nm_connection_new_from_hash:
+ * @hash: (element-type utf8 GLib.HashTable): the #GHashTable describing
+ * the connection
+ *
+ * Creates a new #NMConnection from a hash table describing the connection.  See
+ * nm_connection_to_hash() for a description of the expected hash table.
+ *
+ * Returns: the new #NMConnection object, populated with settings created
+ * from the values in the hash table.
+ **/
+NMConnection *
+_nm_connection_new_from_hash (GHashTable *hash)
+{
+       NMConnection *connection;
+
+       g_return_val_if_fail (hash != NULL, NULL);
+
+       connection = nm_connection_new ();
+       _nm_connection_replace_settings (connection, hash);
+       return connection;
+}
+
 /**
  * nm_connection_new_from_hash:
  * @hash: (element-type utf8 GLib.HashTable): the #GHashTable describing
@@ -1463,11 +1496,9 @@ nm_connection_new_from_hash (GHashTable *hash, GError **error)
        if (!validate_permissions_type (hash, error))
                return NULL;
 
-       connection = nm_connection_new ();
-       if (!hash_to_connection (connection, hash, error)) {
-               g_object_unref (connection);
-               return NULL;
-       }
+       connection = _nm_connection_new_from_hash (hash);
+       if (!nm_connection_verify (connection, error))
+               g_clear_object (&connection);
        return connection;
 }
 
index 6956463..beb8748 100644 (file)
@@ -23,6 +23,8 @@
 
 #include "nm-default.h"
 
+#include "nm-connection.h"
+
 #define NM_SETTING_SECRET_FLAGS_ALL \
        (NM_SETTING_SECRET_FLAG_NONE | \
         NM_SETTING_SECRET_FLAG_AGENT_OWNED | \
@@ -62,6 +64,10 @@ gint _nm_setting_compare_priority (gconstpointer a, gconstpointer b);
 
 gboolean _nm_setting_get_property (NMSetting *setting, const char *name, GValue *value);
 
+NMConnection *_nm_connection_new_from_hash (GHashTable *hash);
+void          _nm_connection_replace_settings (NMConnection *connection,
+                                               GHashTable *new_settings);
+
 typedef enum NMSettingUpdateSecretResult {
        NM_SETTING_UPDATE_SECRET_ERROR              = FALSE,
        NM_SETTING_UPDATE_SECRET_SUCCESS_MODIFIED   = TRUE,
index add3ad9..990d6fe 100644 (file)
@@ -379,9 +379,6 @@ nm_setting_new_from_hash (GType setting_type, GHashTable *hash)
        const char *prop_name;
        GValue *src_value;
        GObjectClass *class;
-       guint n_params = 0;
-       GParameter *params;
-       int i;
 
        g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (setting_type), NULL);
        g_return_val_if_fail (hash != NULL, NULL);
@@ -390,11 +387,11 @@ nm_setting_new_from_hash (GType setting_type, GHashTable *hash)
         * already been used.
         */
        class = g_type_class_ref (setting_type);
-       params = g_new0 (GParameter, g_hash_table_size (hash));
+
+       setting = (NMSetting *) g_object_new (setting_type, NULL);
 
        g_hash_table_iter_init (&iter, hash);
        while (g_hash_table_iter_next (&iter, (gpointer) &prop_name, (gpointer) &src_value)) {
-               GValue *dst_value = &params[n_params].value;
                GParamSpec *param_spec;
 
                param_spec = g_object_class_find_property (class, prop_name);
@@ -402,21 +399,12 @@ nm_setting_new_from_hash (GType setting_type, GHashTable *hash)
                        /* Assume that any unrecognized property either can be ignored, or
                         * else has a backward-compatibility equivalent.
                         */
-                       g_debug ("Ignoring unrecognized property '%s'", prop_name);
                        continue;
                }
 
-               g_value_init (dst_value, G_VALUE_TYPE (src_value));
-               g_value_copy (src_value, dst_value);
-               params[n_params++].name = prop_name;
+               nm_g_object_set_property ((GObject *) setting, prop_name, src_value, NULL);
        }
 
-       setting = (NMSetting *) g_object_newv (setting_type, n_params, params);
-
-       for (i = 0; i < n_params; i++)
-               g_value_unset (&params[i].value);
-
-       g_free (params);
        g_type_class_unref (class);
 
        return setting;
index 57a43ca..a7ecdb5 100644 (file)
@@ -1189,6 +1189,9 @@ nm_client_deactivate_connection_finish (NMClient *client,
  * Returns: (transfer none) (element-type NMRemoteConnection): an array
  * containing all connections provided by the remote settings service.  The
  * returned array is owned by the #NMClient object and should not be modified.
+ *
+ * The connections are as received from D-Bus and might not validate according
+ * to nm_connection_verify().
  **/
 const GPtrArray *
 nm_client_get_connections (NMClient *client)
@@ -1207,6 +1210,9 @@ nm_client_get_connections (NMClient *client)
  *
  * Returns: (transfer none): the remote connection object on success, or %NULL if no
  *  matching object was found.
+ *
+ * The connection is as received from D-Bus and might not validate according
+ * to nm_connection_verify().
  **/
 NMRemoteConnection *
 nm_client_get_connection_by_id (NMClient *client, const char *id)
@@ -1226,6 +1232,9 @@ nm_client_get_connection_by_id (NMClient *client, const char *id)
  *
  * Returns: (transfer none): the remote connection object on success, or %NULL if the object was
  *  not known
+ *
+ * The connection is as received from D-Bus and might not validate according
+ * to nm_connection_verify().
  **/
 NMRemoteConnection *
 nm_client_get_connection_by_path (NMClient *client, const char *path)
@@ -1245,6 +1254,9 @@ nm_client_get_connection_by_path (NMClient *client, const char *path)
  *
  * Returns: (transfer none): the remote connection object on success, or %NULL if the object was
  *  not known
+ *
+ * The connection is as received from D-Bus and might not validate according
+ * to nm_connection_verify().
  **/
 NMRemoteConnection *
 nm_client_get_connection_by_uuid (NMClient *client, const char *uuid)
index 81077be..496dd87 100644 (file)
@@ -2329,6 +2329,9 @@ nm_device_reapply_finish (NMDevice *device,
  * Returns: (transfer full): a %NMConnection with the currently applied settings
  *   or %NULL on error.
  *
+ * The connection is as received from D-Bus and might not validate according
+ * to nm_connection_verify().
+ *
  * Since: 1.2
  **/
 NMConnection *
@@ -2355,7 +2358,7 @@ nm_device_get_applied_connection (NMDevice *device,
                return NULL;
        }
 
-       connection = nm_simple_connection_new_from_dbus (dict, error);
+       connection = _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, error);
        if (!connection)
                return NULL;
 
@@ -2397,7 +2400,7 @@ device_get_applied_connection_cb (GObject *proxy,
                goto out;
        }
 
-       connection = nm_simple_connection_new_from_dbus (dict, &error);
+       connection = _nm_simple_connection_new_from_dbus (dict, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &error);
        if (!connection) {
                g_simple_async_result_take_error (simple, error);
                goto out;
@@ -2457,6 +2460,9 @@ nm_device_get_applied_connection_async  (NMDevice *device,
  * Returns: (transfer full): a currently applied %NMConnection or %NULL in case
  *   of error.
  *
+ * The connection is as received from D-Bus and might not validate according
+ * to nm_connection_verify().
+ *
  * Since: 1.2
  **/
 NMConnection *
index c4a0b6a..eb2874a 100644 (file)
@@ -26,6 +26,7 @@
 #include "nm-dbus-interface.h"
 #include "nm-utils.h"
 #include "nm-setting-connection.h"
+#include "nm-core-internal.h"
 
 #include "nm-remote-connection.h"
 #include "nm-remote-connection-private.h"
@@ -563,13 +564,11 @@ replace_settings (NMRemoteConnection *self, GVariant *new_settings)
 {
        GError *error = NULL;
 
-       if (!nm_connection_replace_settings (NM_CONNECTION (self), new_settings, &error)) {
-               g_warning ("%s: error updating connection %s settings: %s",
-                          __func__,
-                          nm_connection_get_path (NM_CONNECTION (self)),
-                          error->message);
+       if (!_nm_connection_replace_settings ((NMConnection *) self,
+                                             new_settings,
+                                             NM_SETTING_PARSE_FLAGS_BEST_EFFORT,
+                                             &error))
                g_clear_error (&error);
-       }
 }
 
 static void
index 8edb224..60b7a62 100644 (file)
@@ -27,6 +27,7 @@
 #include "nm-enum-types.h"
 #include "nm-dbus-helpers.h"
 #include "nm-simple-connection.h"
+#include "nm-core-internal.h"
 
 #include "nmdbus-secret-agent.h"
 #include "nmdbus-agent-manager.h"
@@ -273,7 +274,7 @@ verify_request (NMSecretAgentOld *self,
 
        /* Make sure the given connection is valid */
        g_assert (out_connection);
-       connection = nm_simple_connection_new_from_dbus (connection_dict, &local);
+       connection = _nm_simple_connection_new_from_dbus (connection_dict, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &local);
        if (connection) {
                nm_connection_set_path (connection, connection_path);
                *out_connection = connection;
index 74861ed..634e61a 100644 (file)
@@ -465,7 +465,7 @@ _connect_generic (NMVpnPluginOld *plugin,
                return;
        }
 
-       connection = nm_simple_connection_new_from_dbus (properties, &error);
+       connection = _nm_simple_connection_new_from_dbus (properties, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &error);
        if (!connection) {
                g_dbus_method_invocation_return_error (context,
                                                       NM_VPN_PLUGIN_ERROR,
@@ -547,7 +547,7 @@ impl_vpn_plugin_old_need_secrets (NMVpnPluginOld *plugin,
        gboolean needed;
        GError *error = NULL;
 
-       connection = nm_simple_connection_new_from_dbus (properties, &error);
+       connection = _nm_simple_connection_new_from_dbus (properties, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &error);
        if (!connection) {
                g_dbus_method_invocation_return_error (context,
                                                       NM_VPN_PLUGIN_ERROR,
@@ -606,7 +606,7 @@ impl_vpn_plugin_old_new_secrets (NMVpnPluginOld *plugin,
                return;
        }
 
-       connection = nm_simple_connection_new_from_dbus (properties, &error);
+       connection = _nm_simple_connection_new_from_dbus (properties, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &error);
        if (!connection) {
                g_dbus_method_invocation_return_error (context,
                                                       NM_VPN_PLUGIN_ERROR,
index 876d479..82e29ee 100644 (file)
@@ -481,7 +481,7 @@ _connect_generic (NMVpnServicePlugin *plugin,
                return;
        }
 
-       connection = nm_simple_connection_new_from_dbus (properties, &error);
+       connection = _nm_simple_connection_new_from_dbus (properties, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &error);
        if (!connection) {
                g_dbus_method_invocation_return_error (context,
                                                       NM_VPN_PLUGIN_ERROR,
@@ -567,7 +567,7 @@ impl_vpn_service_plugin_need_secrets (NMVpnServicePlugin *plugin,
        gboolean needed;
        GError *error = NULL;
 
-       connection = nm_simple_connection_new_from_dbus (properties, &error);
+       connection = _nm_simple_connection_new_from_dbus (properties, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &error);
        if (!connection) {
                g_dbus_method_invocation_return_error (context,
                                                       NM_VPN_PLUGIN_ERROR,
@@ -626,7 +626,7 @@ impl_vpn_service_plugin_new_secrets (NMVpnServicePlugin *plugin,
                return;
        }
 
-       connection = nm_simple_connection_new_from_dbus (properties, &error);
+       connection = _nm_simple_connection_new_from_dbus (properties, NM_SETTING_PARSE_FLAGS_BEST_EFFORT, &error);
        if (!connection) {
                g_dbus_method_invocation_return_error (context,
                                                       NM_VPN_PLUGIN_ERROR,
index 107cc58..3a7c4d5 100644 (file)
@@ -1243,10 +1243,12 @@ _test_connection_invalid_find_connections (gpointer element, gpointer needle, gp
 }
 
 #define ASSERT_IDX(i) \
-       g_assert_cmpint (idx[i], >=, 0); \
-       g_assert (path##i && *path##i); \
-       g_assert (NM_IS_REMOTE_CONNECTION (connections->pdata[idx[i]])); \
-       g_assert_cmpstr (nm_connection_get_path (connections->pdata[idx[i]]), ==, path##i);
+       G_STMT_START { \
+               g_assert_cmpint (idx[i], >=, 0); \
+               g_assert (path##i && *path##i); \
+               g_assert (NM_IS_REMOTE_CONNECTION (connections->pdata[idx[i]])); \
+               g_assert_cmpstr (nm_connection_get_path (connections->pdata[idx[i]]), ==, path##i); \
+       } G_STMT_END
 
 static void
 test_connection_invalid (void)
@@ -1260,12 +1262,14 @@ test_connection_invalid (void)
        gs_free char *path0 = NULL;
        gs_free char *path1 = NULL;
        gs_free char *path2 = NULL;
+       gs_free char *path3 = NULL;
        gs_free char *uuid2 = NULL;
        gsize n_found;
-       gssize idx[3];
+       gssize idx[4];
+       gs_unref_variant GVariant *variant = NULL;
 
        /**************************************************************************
-        * Add two connection before starting libnm. One valid, one invalid.
+        * Add three connections before starting libnm. One valid, two invalid.
         *************************************************************************/
 
        connection = nmtst_create_minimal_connection ("test-connection-invalid-0", NULL, NM_SETTING_WIRED_SETTING_NAME, &s_con);
@@ -1289,6 +1293,21 @@ test_connection_invalid (void)
                                       FALSE,
                                       &path1);
 
+       g_object_set (s_con,
+                     NM_SETTING_CONNECTION_ID, "test-connection-invalid-2",
+                     NM_SETTING_CONNECTION_TYPE, "invalid-type-2",
+                     NM_SETTING_CONNECTION_UUID, nmtst_uuid_generate (),
+                     NULL);
+       variant = nm_connection_to_dbus (connection, NM_CONNECTION_SERIALIZE_ALL);
+       NMTST_VARIANT_EDITOR (variant,
+                             NMTST_VARIANT_ADD_SETTING ("invalid-type-2",
+                                                        nmtst_variant_new_vardict ("some-key1", g_variant_new_string ("some-value1"),
+                                                                                   "some-key2", g_variant_new_uint32 (4722))));
+       g_variant_ref_sink (variant);
+       nmtstc_service_add_connection_variant (my_sinfo,
+                                              variant,
+                                              FALSE,
+                                              &path2);
 
        client = nm_client_new (NULL, &error);
        g_assert_no_error (error);
@@ -1296,19 +1315,21 @@ test_connection_invalid (void)
        connections = nm_client_get_connections (client);
        g_assert (connections);
 
-       g_assert_cmpint (connections->len, ==, 2);
+       g_assert_cmpint (connections->len, ==, 3);
        n_found = nmtst_find_all_indexes (connections->pdata,
                                          connections->len,
-                                         (gpointer *) ((const char *[]) { path0, path1 }),
-                                         2,
+                                         (gpointer *) ((const char *[]) { path0, path1, path2 }),
+                                         3,
                                          _test_connection_invalid_find_connections,
                                          NULL,
                                          idx);
-       g_assert_cmpint (n_found, ==, 2);
+       g_assert_cmpint (n_found, ==, 3);
        ASSERT_IDX (0);
        ASSERT_IDX (1);
+       ASSERT_IDX (2);
        nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[0]]);
        nmtst_assert_connection_unnormalizable (connections->pdata[idx[1]], 0, 0);
+       nmtst_assert_connection_unnormalizable (connections->pdata[idx[2]], 0, 0);
 
        /**************************************************************************
         * After having the client up and running, add another invalid connection
@@ -1322,7 +1343,7 @@ test_connection_invalid (void)
        nmtstc_service_add_connection (my_sinfo,
                                       connection,
                                       FALSE,
-                                      &path2);
+                                      &path3);
 
 
        nmtst_main_loop_run (loop, 100);
@@ -1331,21 +1352,97 @@ test_connection_invalid (void)
        connections = nm_client_get_connections (client);
        g_assert (connections);
 
-       g_assert_cmpint (connections->len, ==, 3);
+       g_assert_cmpint (connections->len, ==, 4);
        n_found = nmtst_find_all_indexes (connections->pdata,
                                          connections->len,
-                                         (gpointer *) ((const char *[]) { path0, path1, path2 }),
-                                         3,
+                                         (gpointer *) ((const char *[]) { path0, path1, path2, path3 }),
+                                         4,
                                          _test_connection_invalid_find_connections,
                                          NULL,
                                          idx);
-       g_assert_cmpint (n_found, ==, 3);
+       g_assert_cmpint (n_found, ==, 4);
+       ASSERT_IDX (0);
+       ASSERT_IDX (1);
+       ASSERT_IDX (2);
+       ASSERT_IDX (3);
+       nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[0]]);
+       nmtst_assert_connection_unnormalizable (connections->pdata[idx[1]], 0, 0);
+       nmtst_assert_connection_unnormalizable (connections->pdata[idx[2]], 0, 0);
+       nmtst_assert_connection_unnormalizable (connections->pdata[idx[3]], 0, 0);
+
+       /**************************************************************************
+        * Modify the invalid connection (still invalid)
+        *************************************************************************/
+
+       NMTST_VARIANT_EDITOR (variant,
+                             NMTST_VARIANT_CHANGE_PROPERTY ("invalid-type-2",
+                                                            "some-key2", "u", 4721));
+       g_variant_ref_sink (variant);
+       nmtstc_service_update_connection_variant (my_sinfo,
+                                                 path2,
+                                                 variant,
+                                                 FALSE);
+
+       nmtst_main_loop_run (loop, 100);
+
+       connections = nm_client_get_connections (client);
+       g_assert (connections);
+
+       g_assert_cmpint (connections->len, ==, 4);
+       n_found = nmtst_find_all_indexes (connections->pdata,
+                                         connections->len,
+                                         (gpointer *) ((const char *[]) { path0, path1, path2, path3 }),
+                                         4,
+                                         _test_connection_invalid_find_connections,
+                                         NULL,
+                                         idx);
+       g_assert_cmpint (n_found, ==, 4);
        ASSERT_IDX (0);
        ASSERT_IDX (1);
        ASSERT_IDX (2);
+       ASSERT_IDX (3);
        nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[0]]);
        nmtst_assert_connection_unnormalizable (connections->pdata[idx[1]], 0, 0);
        nmtst_assert_connection_unnormalizable (connections->pdata[idx[2]], 0, 0);
+       nmtst_assert_connection_unnormalizable (connections->pdata[idx[3]], 0, 0);
+
+       /**************************************************************************
+        * Modify the invalid connection (becomes valid)
+        *************************************************************************/
+
+       NMTST_VARIANT_EDITOR (variant,
+                             NMTST_VARIANT_DROP_SETTING ("invalid-type-2"));
+       NMTST_VARIANT_EDITOR (variant,
+                             NMTST_VARIANT_CHANGE_PROPERTY (NM_SETTING_CONNECTION_SETTING_NAME,
+                                                            NM_SETTING_CONNECTION_TYPE, "s", NM_SETTING_WIRED_SETTING_NAME));
+       g_variant_ref_sink (variant);
+       nmtstc_service_update_connection_variant (my_sinfo,
+                                                 path2,
+                                                 variant,
+                                                 FALSE);
+
+       nmtst_main_loop_run (loop, 100);
+
+       connections = nm_client_get_connections (client);
+       g_assert (connections);
+
+       g_assert_cmpint (connections->len, ==, 4);
+       n_found = nmtst_find_all_indexes (connections->pdata,
+                                         connections->len,
+                                         (gpointer *) ((const char *[]) { path0, path1, path2, path3 }),
+                                         4,
+                                         _test_connection_invalid_find_connections,
+                                         NULL,
+                                         idx);
+       g_assert_cmpint (n_found, ==, 4);
+       ASSERT_IDX (0);
+       ASSERT_IDX (1);
+       ASSERT_IDX (2);
+       ASSERT_IDX (3);
+       nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[0]]);
+       nmtst_assert_connection_unnormalizable (connections->pdata[idx[1]], 0, 0);
+       nmtst_assert_connection_verifies_after_normalization (connections->pdata[idx[2]], 0, 0);
+       nmtst_assert_connection_unnormalizable (connections->pdata[idx[3]], 0, 0);
 
        /**************************************************************************
         * Modify the invalid connection (still invalid)
@@ -1355,7 +1452,7 @@ test_connection_invalid (void)
                      NM_SETTING_CONNECTION_ID, "test-connection-invalid-2x",
                      NULL);
        nmtstc_service_update_connection (my_sinfo,
-                                         path2,
+                                         path3,
                                          connection,
                                          FALSE);
 
@@ -1364,22 +1461,24 @@ test_connection_invalid (void)
        connections = nm_client_get_connections (client);
        g_assert (connections);
 
-       g_assert_cmpint (connections->len, ==, 3);
+       g_assert_cmpint (connections->len, ==, 4);
        n_found = nmtst_find_all_indexes (connections->pdata,
                                          connections->len,
-                                         (gpointer *) ((const char *[]) { path0, path1, path2 }),
-                                         3,
+                                         (gpointer *) ((const char *[]) { path0, path1, path2, path3 }),
+                                         4,
                                          _test_connection_invalid_find_connections,
                                          NULL,
                                          idx);
-       g_assert_cmpint (n_found, ==, 3);
+       g_assert_cmpint (n_found, ==, 4);
        ASSERT_IDX (0);
        ASSERT_IDX (1);
        ASSERT_IDX (2);
+       ASSERT_IDX (3);
        nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[0]]);
        nmtst_assert_connection_unnormalizable (connections->pdata[idx[1]], 0, 0);
-       nmtst_assert_connection_unnormalizable (connections->pdata[idx[2]], 0, 0);
-       g_assert_cmpstr ("test-connection-invalid-2x", ==, nm_connection_get_id (connections->pdata[idx[2]]));
+       nmtst_assert_connection_verifies_after_normalization (connections->pdata[idx[2]], 0, 0);
+       nmtst_assert_connection_unnormalizable (connections->pdata[idx[3]], 0, 0);
+       g_assert_cmpstr ("test-connection-invalid-2x", ==, nm_connection_get_id (connections->pdata[idx[3]]));
 
        /**************************************************************************
         * Modify the invalid connection (now becomes valid)
@@ -1395,7 +1494,7 @@ test_connection_invalid (void)
                      NULL);
 
        nmtstc_service_update_connection (my_sinfo,
-                                         path2,
+                                         path3,
                                          connection,
                                          FALSE);
 
@@ -1404,22 +1503,24 @@ test_connection_invalid (void)
        connections = nm_client_get_connections (client);
        g_assert (connections);
 
-       g_assert_cmpint (connections->len, ==, 3);
+       g_assert_cmpint (connections->len, ==, 4);
        n_found = nmtst_find_all_indexes (connections->pdata,
                                          connections->len,
-                                         (gpointer *) ((const char *[]) { path0, path1, path2 }),
-                                         3,
+                                         (gpointer *) ((const char *[]) { path0, path1, path2, path3 }),
+                                         4,
                                          _test_connection_invalid_find_connections,
                                          NULL,
                                          idx);
-       g_assert_cmpint (n_found, ==, 3);
+       g_assert_cmpint (n_found, ==, 4);
        ASSERT_IDX (0);
        ASSERT_IDX (1);
        ASSERT_IDX (2);
+       ASSERT_IDX (3);
        nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[0]]);
        nmtst_assert_connection_unnormalizable (connections->pdata[idx[1]], 0, 0);
-       nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[2]]);
-       g_assert_cmpstr ("test-connection-invalid-2z", ==, nm_connection_get_id (connections->pdata[idx[2]]));
+       nmtst_assert_connection_verifies_after_normalization (connections->pdata[idx[2]], 0, 0);
+       nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[3]]);
+       g_assert_cmpstr ("test-connection-invalid-2z", ==, nm_connection_get_id (connections->pdata[idx[3]]));
 
        /**************************************************************************
         * Modify the invalid connection and make it valid
@@ -1444,23 +1545,25 @@ test_connection_invalid (void)
        connections = nm_client_get_connections (client);
        g_assert (connections);
 
-       g_assert_cmpint (connections->len, ==, 3);
+       g_assert_cmpint (connections->len, ==, 4);
        n_found = nmtst_find_all_indexes (connections->pdata,
                                          connections->len,
-                                         (gpointer *) ((const char *[]) { path0, path1, path2 }),
-                                         3,
+                                         (gpointer *) ((const char *[]) { path0, path1, path2, path3 }),
+                                         4,
                                          _test_connection_invalid_find_connections,
                                          NULL,
                                          idx);
-       g_assert_cmpint (n_found, ==, 3);
+       g_assert_cmpint (n_found, ==, 4);
        ASSERT_IDX (0);
        ASSERT_IDX (1);
        ASSERT_IDX (2);
+       ASSERT_IDX (3);
        nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[0]]);
        nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[1]]);
-       nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[2]]);
+       nmtst_assert_connection_verifies_after_normalization (connections->pdata[idx[2]], 0, 0);
+       nmtst_assert_connection_verifies_without_normalization (connections->pdata[idx[3]]);
        g_assert_cmpstr ("test-connection-invalid-1x", ==, nm_connection_get_id (connections->pdata[idx[1]]));
-       g_assert_cmpstr ("test-connection-invalid-2z", ==, nm_connection_get_id (connections->pdata[idx[2]]));
+       g_assert_cmpstr ("test-connection-invalid-2z", ==, nm_connection_get_id (connections->pdata[idx[3]]));
 
 #undef ASSERT_IDX
 }
index 9c37b7e..b247e54 100644 (file)
@@ -140,6 +140,7 @@ libnm/nm-remote-settings.c
 libnm/nm-vpn-plugin-old.c
 libnm/nm-vpn-service-plugin.c
 policy/org.freedesktop.NetworkManager.policy.in.in
+shared/nm-shared-utils.c
 src/NetworkManagerUtils.c
 src/main.c
 src/main-utils.c
index 03fad12..c042fdb 100644 (file)
@@ -4,6 +4,8 @@ EXTRA_DIST = \
      nm-default.h \
      nm-glib.h \
      nm-macros-internal.h \
+     nm-shared-utils.c \
+     nm-shared-utils.h \
      nm-test-libnm-utils.h \
      nm-test-utils.h \
      nm-test-utils-impl.c \
index 3652777..aae4777 100644 (file)
@@ -52,6 +52,7 @@
 #include "nm-version.h"
 #include "gsystem-local-alloc.h"
 #include "nm-macros-internal.h"
+#include "nm-shared-utils.h"
 
 /*****************************************************************************/
 
index 152cbf6..4176231 100644 (file)
 #define nm_auto_free nm_auto(_nm_auto_free_impl)
 GS_DEFINE_CLEANUP_FUNCTION(void*, _nm_auto_free_impl, free)
 
+static inline void
+_nm_auto_unset_gvalue_impl (GValue *v)
+{
+       g_value_unset (v);
+}
+#define nm_auto_unset_gvalue nm_auto(_nm_auto_unset_gvalue_impl)
+
 /********************************************************/
 
 /* http://stackoverflow.com/a/11172679 */
diff --git a/shared/nm-shared-utils.c b/shared/nm-shared-utils.c
new file mode 100644 (file)
index 0000000..0ae54bd
--- /dev/null
@@ -0,0 +1,228 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2016 Red Hat, Inc.
+ */
+
+#include "nm-default.h"
+
+#include "nm-shared-utils.h"
+
+#include <errno.h>
+
+/*****************************************************************************/
+
+/* _nm_utils_ascii_str_to_int64:
+ *
+ * A wrapper for g_ascii_strtoll, that checks whether the whole string
+ * can be successfully converted to a number and is within a given
+ * range. On any error, @fallback will be returned and %errno will be set
+ * to a non-zero value. On success, %errno will be set to zero, check %errno
+ * for errors. Any trailing or leading (ascii) white space is ignored and the
+ * functions is locale independent.
+ *
+ * The function is guaranteed to return a value between @min and @max
+ * (inclusive) or @fallback. Also, the parsing is rather strict, it does
+ * not allow for any unrecognized characters, except leading and trailing
+ * white space.
+ **/
+gint64
+_nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback)
+{
+       gint64 v;
+       size_t len;
+       char buf[64], *s, *str_free = NULL;
+
+       if (str) {
+               while (g_ascii_isspace (str[0]))
+                       str++;
+       }
+       if (!str || !str[0]) {
+               errno = EINVAL;
+               return fallback;
+       }
+
+       len = strlen (str);
+       if (g_ascii_isspace (str[--len])) {
+               /* backward search the first non-ws character.
+                * We already know that str[0] is non-ws. */
+               while (g_ascii_isspace (str[--len]))
+                       ;
+
+               /* str[len] is now the last non-ws character... */
+               len++;
+
+               if (len >= sizeof (buf))
+                       s = str_free = g_malloc (len + 1);
+               else
+                       s = buf;
+
+               memcpy (s, str, len);
+               s[len] = 0;
+
+               nm_assert (len > 0 && len < strlen (str) && len == strlen (s));
+               nm_assert (!g_ascii_isspace (str[len-1]) && g_ascii_isspace (str[len]));
+               nm_assert (strncmp (str, s, len) == 0);
+
+               str = s;
+       }
+
+       errno = 0;
+       v = g_ascii_strtoll (str, &s, base);
+
+       if (errno != 0)
+               v = fallback;
+       else if (s[0] != 0) {
+               errno = EINVAL;
+               v = fallback;
+       } else if (v > max || v < min) {
+               errno = ERANGE;
+               v = fallback;
+       }
+
+       if (G_UNLIKELY (str_free))
+               g_free (str_free);
+       return v;
+}
+
+/*****************************************************************************/
+
+G_DEFINE_QUARK (nm-utils-error-quark, nm_utils_error)
+
+void
+nm_utils_error_set_cancelled (GError **error,
+                              gboolean is_disposing,
+                              const char *instance_name)
+{
+       if (is_disposing) {
+               g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING,
+                            "Disposing %s instance",
+                            instance_name && *instance_name ? instance_name : "source");
+       } else {
+               g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
+                                    "Request cancelled");
+       }
+}
+
+gboolean
+nm_utils_error_is_cancelled (GError *error,
+                             gboolean consider_is_disposing)
+{
+       if (error) {
+               if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
+                       return TRUE;
+               if (   consider_is_disposing
+                   && g_error_matches (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING))
+                       return TRUE;
+       }
+       return FALSE;
+}
+
+/*****************************************************************************/
+
+/**
+ * nm_g_object_set_property:
+ * @object: the target object
+ * @property_name: the property name
+ * @value: the #GValue to set
+ * @error: (allow-none): optional error argument
+ *
+ * A reimplementation of g_object_set_property(), but instead
+ * returning an error instead of logging a warning. All g_object_set*()
+ * versions in glib require you to not pass invalid types or they will
+ * log a g_warning() -- without reporting an error. We don't want that,
+ * so we need to hack error checking around it.
+ *
+ * Returns: whether the value was successfully set.
+ */
+gboolean
+nm_g_object_set_property (GObject *object,
+                          const gchar  *property_name,
+                          const GValue *value,
+                          GError **error)
+{
+       GParamSpec *pspec;
+       nm_auto_unset_gvalue GValue tmp_value = G_VALUE_INIT;
+       GObjectClass *klass;
+
+       g_return_val_if_fail (G_IS_OBJECT (object), FALSE);
+       g_return_val_if_fail (property_name != NULL, FALSE);
+       g_return_val_if_fail (G_IS_VALUE (value), FALSE);
+       g_return_val_if_fail (!error || !*error, FALSE);
+
+       /* g_object_class_find_property() does g_param_spec_get_redirect_target(),
+        * where we differ from a plain g_object_set_property(). */
+       pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), property_name);
+
+       if (!pspec) {
+               g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+                            _("object class '%s' has no property named '%s'"),
+                            G_OBJECT_TYPE_NAME (object),
+                            property_name);
+               return FALSE;
+       }
+       if (!(pspec->flags & G_PARAM_WRITABLE)) {
+               g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+                            _("property '%s' of object class '%s' is not writable"),
+                            pspec->name,
+                            G_OBJECT_TYPE_NAME (object));
+               return FALSE;
+       }
+       if ((pspec->flags & G_PARAM_CONSTRUCT_ONLY)) {
+               g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+                            _("construct property \"%s\" for object '%s' can't be set after construction"),
+                            pspec->name, G_OBJECT_TYPE_NAME (object));
+               return FALSE;
+       }
+
+       klass = g_type_class_peek (pspec->owner_type);
+       if (klass == NULL) {
+               g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+                            _("'%s::%s' is not a valid property name; '%s' is not a GObject subtype"),
+                           g_type_name (pspec->owner_type), pspec->name, g_type_name (pspec->owner_type));
+               return FALSE;
+       }
+
+       /* provide a copy to work from, convert (if necessary) and validate */
+       g_value_init (&tmp_value, pspec->value_type);
+       if (!g_value_transform (value, &tmp_value)) {
+               g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+                            _("unable to set property '%s' of type '%s' from value of type '%s'"),
+                            pspec->name,
+                            g_type_name (pspec->value_type),
+                            G_VALUE_TYPE_NAME (value));
+               return FALSE;
+       }
+       if (   g_param_value_validate (pspec, &tmp_value)
+           && !(pspec->flags & G_PARAM_LAX_VALIDATION)) {
+               gs_free char *contents = g_strdup_value_contents (value);
+
+               g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_UNKNOWN,
+                            _("value \"%s\" of type '%s' is invalid or out of range for property '%s' of type '%s'"),
+                            contents,
+                            G_VALUE_TYPE_NAME (value),
+                            pspec->name,
+                            g_type_name (pspec->value_type));
+               return FALSE;
+       }
+
+       g_object_set_property (object, property_name, &tmp_value);
+       return TRUE;
+}
+
+/*****************************************************************************/
diff --git a/shared/nm-shared-utils.h b/shared/nm-shared-utils.h
new file mode 100644 (file)
index 0000000..f80c850
--- /dev/null
@@ -0,0 +1,63 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2016 Red Hat, Inc.
+ */
+
+#ifndef __NM_SHARED_UTILS_H__
+#define __NM_SHARED_UTILS_H__
+
+/******************************************************************************/
+
+gint64 _nm_utils_ascii_str_to_int64 (const char *str, guint base, gint64 min, gint64 max, gint64 fallback);
+
+/******************************************************************************/
+
+/**
+ * NMUtilsError:
+ * @NM_UTILS_ERROR_UNKNOWN: unknown or unclassified error
+ * @NM_UTILS_ERROR_CANCELLED_DISPOSING: when disposing an object that has
+ *   pending aynchronous operations, the operation is cancelled with this
+ *   error reason. Depending on the usage, this might indicate a bug because
+ *   usually the target object should stay alive as long as there are pending
+ *   operations.
+ */
+typedef enum {
+       NM_UTILS_ERROR_UNKNOWN = 0,                 /*< nick=Unknown >*/
+       NM_UTILS_ERROR_CANCELLED_DISPOSING,         /*< nick=CancelledDisposing >*/
+} NMUtilsError;
+
+#define NM_UTILS_ERROR (nm_utils_error_quark ())
+GQuark nm_utils_error_quark (void);
+
+void nm_utils_error_set_cancelled (GError **error,
+                                   gboolean is_disposing,
+                                   const char *instance_name);
+gboolean nm_utils_error_is_cancelled (GError *error,
+                                      gboolean consider_is_disposing);
+
+/******************************************************************************/
+
+gboolean nm_g_object_set_property (GObject *object,
+                                   const gchar  *property_name,
+                                   const GValue *value,
+                                   GError **error);
+
+/******************************************************************************/
+
+#endif /* __NM_SHARED_UTILS_H__ */
index a7d0f93..2503245 100644 (file)
@@ -1793,6 +1793,27 @@ nmtst_create_connection_from_keyfile (const char *keyfile_str, const char *keyfi
 
 #ifdef __NM_CONNECTION_H__
 
+inline static GVariant *
+_nmtst_variant_new_vardict (int dummy, ...)
+{
+       GVariantBuilder builder;
+       va_list ap;
+       const char *name;
+       GVariant *variant;
+
+       g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
+
+       va_start (ap, dummy);
+       while ((name = va_arg (ap, const char *))) {
+               variant = va_arg (ap, GVariant *);
+               g_variant_builder_add (&builder, "{sv}", name, variant);
+       }
+       va_end (ap);
+
+       return g_variant_builder_end (&builder);
+}
+#define nmtst_variant_new_vardict(...) _nmtst_variant_new_vardict (0, __VA_ARGS__, NULL)
+
 #define nmtst_assert_variant_is_of_type(variant, type) \
        G_STMT_START { \
                GVariant *_variantx = (variant); \
@@ -1863,6 +1884,8 @@ typedef enum {
                         \
                        if (__cur_setting_name) \
                                g_variant_builder_add (&__connection_builder, "{sa{sv}}", __cur_setting_name, &__setting_builder); \
+                       else \
+                               g_variant_builder_clear (&__setting_builder); \
                        g_variant_iter_free (__setting_iter); \
                } \
                 \
index 4f92ec1..33d33fa 100644 (file)
@@ -7369,7 +7369,10 @@ impl_device_reapply (NMDevice *self,
 
        if (settings && g_variant_n_children (settings)) {
                /* New settings specified inline. */
-               connection = nm_simple_connection_new_from_dbus (settings, &error);
+               connection = _nm_simple_connection_new_from_dbus (settings,
+                                                                   NM_SETTING_PARSE_FLAGS_STRICT
+                                                                 | NM_SETTING_PARSE_FLAGS_NORMALIZE,
+                                                                 &error);
                if (!connection) {
                        g_prefix_error (&error, "The settings specified are invalid: ");
                        nm_audit_log_device_op (NM_AUDIT_OP_DEVICE_REAPPLY, self, FALSE, context, error->message);
index 1a6d00f..b98b6e8 100644 (file)
@@ -109,39 +109,6 @@ _nm_utils_set_testing (NMUtilsTestFlags flags)
 
 /*****************************************************************************/
 
-G_DEFINE_QUARK (nm-utils-error-quark, nm_utils_error)
-
-void
-nm_utils_error_set_cancelled (GError **error,
-                              gboolean is_disposing,
-                              const char *instance_name)
-{
-       if (is_disposing) {
-               g_set_error (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING,
-                            "Disposing %s instance",
-                            instance_name && *instance_name ? instance_name : "source");
-       } else {
-               g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
-                                    "Request cancelled");
-       }
-}
-
-gboolean
-nm_utils_error_is_cancelled (GError *error,
-                             gboolean consider_is_disposing)
-{
-       if (error) {
-               if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
-                       return TRUE;
-               if (   consider_is_disposing
-                   && g_error_matches (error, NM_UTILS_ERROR, NM_UTILS_ERROR_CANCELLED_DISPOSING))
-                       return TRUE;
-       }
-       return FALSE;
-}
-
-/*****************************************************************************/
-
 static GSList *_singletons = NULL;
 static gboolean _singletons_shutdown = FALSE;
 
index 2fb5273..f77b43e 100644 (file)
@@ -91,31 +91,6 @@ GETTER (void) \
 
 /*****************************************************************************/
 
-/**
- * NMUtilsError:
- * @NM_UTILS_ERROR_UNKNOWN: unknown or unclassified error
- * @NM_UTILS_ERROR_CANCELLED_DISPOSING: when disposing an object that has
- *   pending aynchronous operations, the operation is cancelled with this
- *   error reason. Depending on the usage, this might indicate a bug because
- *   usually the target object should stay alive as long as there are pending
- *   operations.
- */
-typedef enum {
-       NM_UTILS_ERROR_UNKNOWN = 0,                 /*< nick=Unknown >*/
-       NM_UTILS_ERROR_CANCELLED_DISPOSING,         /*< nick=CancelledDisposing >*/
-} NMUtilsError;
-
-#define NM_UTILS_ERROR (nm_utils_error_quark ())
-GQuark nm_utils_error_quark (void);
-
-void nm_utils_error_set_cancelled (GError **error,
-                                   gboolean is_disposing,
-                                   const char *instance_name);
-gboolean nm_utils_error_is_cancelled (GError *error,
-                                      gboolean consider_is_disposing);
-
-/*****************************************************************************/
-
 gint nm_utils_ascii_str_to_bool (const char *str,
                                  gint default_value);
 
index 0606553..ba52d52 100644 (file)
@@ -3599,7 +3599,7 @@ impl_manager_add_and_activate_connection (NMManager *self,
         */
        connection = nm_simple_connection_new ();
        if (settings && g_variant_n_children (settings))
-               nm_connection_replace_settings (connection, settings, NULL);
+               _nm_connection_replace_settings (connection, settings, NM_SETTING_PARSE_FLAGS_STRICT, NULL);
 
        subject = validate_activation_request (self,
                                               context,
index 10aa77a..6bed3fe 100644 (file)
@@ -1735,7 +1735,10 @@ settings_connection_update_helper (NMSettingsConnection *self,
 
        /* Check if the settings are valid first */
        if (new_settings) {
-               tmp = nm_simple_connection_new_from_dbus (new_settings, &error);
+               tmp = _nm_simple_connection_new_from_dbus (new_settings,
+                                                            NM_SETTING_PARSE_FLAGS_STRICT
+                                                          | NM_SETTING_PARSE_FLAGS_NORMALIZE,
+                                                          &error);
                if (!tmp)
                        goto error;
        }
index f090185..77e45f4 100644 (file)
@@ -1407,7 +1407,10 @@ impl_settings_add_connection_helper (NMSettings *self,
        NMConnection *connection;
        GError *error = NULL;
 
-       connection = nm_simple_connection_new_from_dbus (settings, &error);
+       connection = _nm_simple_connection_new_from_dbus (settings,
+                                                           NM_SETTING_PARSE_FLAGS_STRICT
+                                                         | NM_SETTING_PARSE_FLAGS_NORMALIZE,
+                                                         &error);
 
        if (connection) {
                if (!nm_connection_verify_secrets (connection, &error))