[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#593249: [CVE 2010-1172] future unblock: dbus-glib/0.88-2



Package: release.debian.org
Severity: normal
User: release.debian.org@packages.debian.org
Usertags: freeze-exception
Tags: security

Colin Walters has released dbus-glib 0.88, with a security fix for system-bus
services that use dbus-glib (CVE 2010-1172,
http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=592753, Red Hat #585394,
LP #616517).

The diffstat is somewhat intimidating, but I believe that taking all of 0.88
is a better option for squeeze than backporting the security fix to 0.86,
because:

- the majority of the changes are the single commit that adds the security fix
- the majority of the *other* changes are also targeted bugfixes
- the security fix adds ABI (to let system services tell dbus-glib which
  properties they intended to export), so it's a mini-transition already

The potentially-vulnerable services can be approximated as those that install
a file in /etc/dbus-1/system.d and depend on dbus-glib. Fedora people have
already checked several system-bus services; see the bug.

After uploading the version with the security fix, system services that are
vulnerable will need rebuilding against it. The new version of
dbus-binding-tool should arrange for the right data structures to appear,
without source changes.

I'm not investigating lenny at this stage; I suspect this will be hard to fix
there. I've uploaded dbus-glib 0.88-1 to experimental while awaiting release
team feedback.

diffstat for the security fix (commit 510bdcd63ae4e58), excluding the tests:
 dbus/dbus-binding-tool-glib.c |   53 ++++++--
 dbus/dbus-glib.h              |    2 +
 dbus/dbus-gobject.c           |  293 +++++++++++++++++++++++++++++++++++------
 3 files changed, 293 insertions(+), 55 deletions(-)

diffstat for the unrelated upstream changes, excluding tests and examples:
 .gitignore                           |   12 +++
 configure.ac                         |    4 +-
 dbus/dbus-gidl.h                     |    2 +-
 dbus/dbus-glib.h                     |    6 +-
 dbus/dbus-gobject.c                  |   52 ++++++++++----
 dbus/dbus-gproxy.c                   |    9 +--
 dbus/dbus-gtype-specialized.c        |  129 ++++++++++++++++++++++++++++++++++
 dbus/dbus-gtype-specialized.h        |    2 +
 doc/reference/dbus-glib-sections.txt |   10 +++
 9 files changed, 202 insertions(+), 24 deletions(-)

Summary of the unrelated changes:
- new feature: dbus_g_value_build_g_variant(), a new function which doesn't
  alter any existing code (it does add a GLib 2.24 dependency, but squeeze
  already has that)
- fix for a use-after-free in dbus-gproxy.c when cancelling calls
- fix for a use-after-free in dbus-gobject.c when "shadow properties" are used
- fix for a libdbus warning if an unregistered error is raised
- allow the same object path to be used twice if the connection is different
- rename arguments called "interface" to "iface" to be nice to Windows
- documentation fixes in dbus-gproxy.c, dbus-gobject.c, dbus-glib-sections.txt
- disabling one of the tests on Windows
- build-system fixes for some tests and examples

Diffs attached:
- 086-to-before-security.diff are the unrelated changes
- security.diff is the actual security fix
- the only change after that is to bump the version to 0.88 in configure.ac
- debian.diff is the diff for the debian directory, from squeeze's 0.86-1 to
  experimental's 0.88-1
- I request approval to upload the same changes to sid, and hence squeeze

Regards,
    Simon
obtained in upstream git repo with: git diff dbus-glib-0.86..510bdcd63~

diff --git a/.gitignore b/.gitignore
index 75895c6..dfa60c2 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,6 +23,8 @@ dbus-glib-1.pc
 dbus-glib-1-uninstalled.pc
 dbus/Makefile
 dbus/Makefile.in
+/dbus/dbus-bash-completion-helper
+/dbus/dbus-bash-completion.sh
 dbus/dbus-binding-tool
 dbus/dbus-glib-error-enum.h
 dbus/dbus-glib-error-switch.h
@@ -76,22 +78,32 @@ libtool
 ltmain.sh
 m4/Makefile
 m4/Makefile.in
+/m4/libtool.m4
+/m4/ltoptions.m4
+/m4/ltsugar.m4
+/m4/ltversion.m4
+/m4/lt~obsolete.m4
 missing
 stamp-h1
 test/Makefile
 test/Makefile.in
 test/core/Makefile
 test/core/Makefile.in
+/test/core/test-5688
 test/core/my-object-marshal.c
 test/core/my-object-marshal.h
 test/core/run-with-tmp-session-bus.conf
 test/core/test-dbus-glib
+/test/core/test-gvariant
 test/core/test-profile
 test/core/test-service-glib
 test/core/test-service-glib-bindings.h
 test/core/test-service-glib-glue.h
+/test/core/test-service-glib-subclass-glue.h
 test/core/test-thread-client
 test/core/test-thread-server
+/test/core/test-unregister
+/test/core/test-variant-recursion
 test/data/valid-service-files/debug-echo.service
 test/data/valid-service-files/debug-glib.service
 test/data/valid-service-files/test-interfaces.service.in
diff --git a/configure.ac b/configure.ac
index 4257be4..15d1b6d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3,7 +3,7 @@ AC_PREREQ(2.52)
 
 AC_INIT(dbus-glib, 0.86, [https://bugs.freedesktop.org/enter_bug.cgi?product=dbus])
 
-AC_CANONICAL_TARGET
+AC_CANONICAL_HOST
 
 AM_INIT_AUTOMAKE([1.9])
 
@@ -385,7 +385,7 @@ fi
 AC_SUBST(DBUS_DAEMONDIR)
 
 # Glib detection
-PKG_CHECK_MODULES(DBUS_GLIB, gobject-2.0 >= 2.10, have_glib=yes, have_glib=no)
+PKG_CHECK_MODULES(DBUS_GLIB, gobject-2.0 >= 2.24, have_glib=yes, have_glib=no)
 PKG_CHECK_MODULES(DBUS_GLIB_THREADS, gthread-2.0 >= 2.6, have_glib_threads=yes, have_glib_threads=no)
 
 if test x$have_glib = xno ; then
diff --git a/dbus/dbus-gidl.h b/dbus/dbus-gidl.h
index dd82176..b766bcb 100644
--- a/dbus/dbus-gidl.h
+++ b/dbus/dbus-gidl.h
@@ -80,7 +80,7 @@ const char*         node_info_get_name            (NodeInfo            *info);
 GSList*             node_info_get_interfaces      (NodeInfo            *info);
 GSList*             node_info_get_nodes           (NodeInfo            *info);
 void                node_info_add_interface       (NodeInfo            *info,
-                                                   InterfaceInfo       *interface);
+                                                   InterfaceInfo       *iface);
 void                node_info_add_node            (NodeInfo            *info,
                                                    NodeInfo            *child);
 void                node_info_replace_node        (NodeInfo            *info,
diff --git a/dbus/dbus-glib.h b/dbus/dbus-glib.h
index 256f817..1b236d8 100644
--- a/dbus/dbus-glib.h
+++ b/dbus/dbus-glib.h
@@ -233,14 +233,14 @@ GType             dbus_g_proxy_get_type              (void) G_GNUC_CONST;
 DBusGProxy*       dbus_g_proxy_new_for_name          (DBusGConnection   *connection,
                                                       const char        *name,
                                                       const char        *path,
-                                                      const char        *interface);
+                                                      const char        *iface);
 DBusGProxy*       dbus_g_proxy_new_for_name_owner    (DBusGConnection   *connection,
                                                       const char        *name,
                                                       const char        *path,
-                                                      const char        *interface,
+                                                      const char        *iface,
                                                       GError           **error);
 DBusGProxy*       dbus_g_proxy_new_from_proxy        (DBusGProxy        *proxy,
-                                                      const char        *interface,
+                                                      const char        *iface,
                                                       const char        *path_name);
 DBusGProxy*       dbus_g_proxy_new_for_peer          (DBusGConnection   *connection,
                                                       const char        *path_name,
diff --git a/dbus/dbus-gobject.c b/dbus/dbus-gobject.c
index 3e7914d..6a1aba4 100644
--- a/dbus/dbus-gobject.c
+++ b/dbus/dbus-gobject.c
@@ -945,7 +945,8 @@ lookup_property_name (GObject    *object,
   if (shadow_props)
     {
       shadow_prop_name = g_strdup (g_hash_table_lookup (shadow_props, wincaps_propname));
-      g_free (uscore_name);
+      if (shadow_prop_name)
+        g_free (uscore_name);
     }
 
   return shadow_prop_name ? shadow_prop_name : uscore_name;
@@ -1218,16 +1219,21 @@ gerror_domaincode_to_dbus_error_name (const DBusGObjectInfo *object_info,
 
   if (!domain_str || !code_str)
     {
+      const char *domain_string;
       /* If we can't map it sensibly, make up an error name */
-      char *domain_from_quark;
       
       dbus_error_name = g_string_new ("org.freedesktop.DBus.GLib.UnmappedError.");
 
-      domain_from_quark = uscore_to_wincaps (g_quark_to_string (domain));
-      g_string_append (dbus_error_name, domain_from_quark);
-      g_free (domain_from_quark);
-	
-      g_string_append_printf (dbus_error_name, ".Code%d", code);
+      domain_string = g_quark_to_string (domain);
+      if (domain_string != NULL)
+        {
+          char *uscored = uscore_to_wincaps (domain_string);
+          g_string_append (dbus_error_name, uscored);
+          g_string_append_c (dbus_error_name, '.');
+          g_free (uscored);
+        }
+
+      g_string_append_printf (dbus_error_name, "Code%d", code);
     }
   else
     {
@@ -2190,13 +2196,33 @@ dbus_g_object_type_install_info (GType                  object_type,
 
 /**
  * dbus_g_error_domain_register:
- * @domain: the #GError domain 
- * @default_iface: the D-BUS interface used for error values by default, or #NULL
+ * @domain: the #GError domain
+ * @default_iface: the prefix used for error values, or %NULL
  * @code_enum: a #GType for a #GEnum of the error codes
  *
- * Register a #GError domain and set of codes with D-BUS.  You must
- * have created a GEnum for the error codes.  This function will not
- * be needed with an introspection-capable GLib.
+ * Register a #GError domain and set of codes with D-Bus. When an object
+ * raises a #GError in the domain @domain from one of its D-Bus methods,
+ * the D-Bus error name used will be @default_iface, followed by a dot,
+ * followed by the #GEnumValue.value_nick corresponding to the #GError.code.
+ * For D-Bus, it's conventional to use an error name (value_nick) that is
+ * in CamelCase.
+ *
+ * (For instance, if a D-Bus method <code>com.example.MyObject.GetThings</code>
+ * can raise a #GError with domain <code>MY_ERROR</code> and code
+ * <code>MY_ERROR_NOT_HAPPY</code>, you could call
+ * <code>dbus_g_error_domain_register (MY_ERROR, "com.example.MyError",
+ * MY_TYPE_ERROR)</code>, and set up the value_nick for
+ * <code>MY_ERROR_NOT_HAPPY</code> to be <code>NotHappy</code>,
+ * resulting in the D-Bus error string
+ * <code>com.example.MyError.NotHappy</code>.)
+ *
+ * If @default_iface is %NULL, the D-Bus interface of the method that failed
+ * will be used.
+ *
+ * (For instance, if the above example had called
+ * <code>dbus_g_error_domain_register (MY_ERROR, NULL, MY_TYPE_ERROR)</code>
+ * instead, then the D-Bus error string would be
+ * <code>com.example.MyObject.NotHappy</code>.)
  */
 void
 dbus_g_error_domain_register (GQuark                domain,
@@ -2324,7 +2350,7 @@ dbus_g_connection_register_g_object (DBusGConnection       *connection,
       o = iter->data;
 
       /* Silently ignore duplicate registrations */
-      if (strcmp (o->object_path, at_path) == 0)
+      if (strcmp (o->object_path, at_path) == 0 && o->connection == connection)
         return;
     }
 
diff --git a/dbus/dbus-gproxy.c b/dbus/dbus-gproxy.c
index f8a2828..1e7331f 100644
--- a/dbus/dbus-gproxy.c
+++ b/dbus/dbus-gproxy.c
@@ -2418,7 +2418,7 @@ dbus_g_proxy_end_call_internal (DBusGProxy        *proxy,
  *
  * Asynchronously invokes a method on a remote interface. The method
  * call will not be sent over the wire until the application returns
- * to the main loop, or blocks in dbus_connection_flush() to write out
+ * to the main loop, or blocks in dbus_g_connection_flush() to write out
  * pending data.  The call will be completed after a timeout, or when
  * a reply is received.  When the call returns, the callback specified
  * will be invoked; you can then collect the results of the call
@@ -2471,7 +2471,7 @@ dbus_g_proxy_begin_call (DBusGProxy          *proxy,
  *
  * Asynchronously invokes a method on a remote interface. The method
  * call will not be sent over the wire until the application returns
- * to the main loop, or blocks in dbus_connection_flush() to write out
+ * to the main loop, or blocks in dbus_g_connection_flush() to write out
  * pending data.  The call will be completed after a timeout, or when
  * a reply is received.  When the call returns, the callback specified
  * will be invoked; you can then collect the results of the call
@@ -2740,11 +2740,10 @@ dbus_g_proxy_cancel_call (DBusGProxy        *proxy,
   call_id = DBUS_G_PROXY_CALL_TO_ID (call);
 
   pending = g_hash_table_lookup (priv->pending_calls, GUINT_TO_POINTER (call_id));
+  g_hash_table_remove (priv->pending_calls, GUINT_TO_POINTER (call_id));
   g_return_if_fail (pending != NULL);
 
   dbus_pending_call_cancel (pending);
-
-  g_hash_table_remove (priv->pending_calls, GUINT_TO_POINTER (call_id));
 }
 
 /**
@@ -2756,7 +2755,7 @@ dbus_g_proxy_cancel_call (DBusGProxy        *proxy,
  * Sends a message to the interface we're proxying for.  Does not
  * block or wait for a reply. The message is only actually written out
  * when you return to the main loop or block in
- * dbus_connection_flush().
+ * dbus_g_connection_flush().
  *
  * The message is modified to be addressed to the target interface.
  * That is, a destination name field or whatever is needed will be
diff --git a/dbus/dbus-gtype-specialized.c b/dbus/dbus-gtype-specialized.c
index fa22eee..fc841c6 100644
--- a/dbus/dbus-gtype-specialized.c
+++ b/dbus/dbus-gtype-specialized.c
@@ -22,6 +22,7 @@
  *
  */
 
+#include "dbus-glib.h"
 #include "dbus-gtype-specialized-priv.h"
 #include "dbus-gvalue-utils.h"
 #include <glib.h>
@@ -1094,3 +1095,131 @@ error:
   return FALSE;
 }
 
+static void
+_collection_iterator (const GValue *value,
+    gpointer user_data)
+{
+  GPtrArray *children = user_data;
+
+  g_ptr_array_add (children, dbus_g_value_build_g_variant (value));
+}
+
+static void
+_map_iterator (const GValue *kvalue,
+    const GValue *vvalue,
+    gpointer user_data)
+{
+  GPtrArray *children = user_data;
+
+  g_ptr_array_add (children,
+      g_variant_new_dict_entry (
+        dbus_g_value_build_g_variant (kvalue),
+        dbus_g_value_build_g_variant (vvalue)));
+}
+
+/**
+ * dbus_g_value_build_g_variant:
+ * @value: a simple or specialized #GValue to convert to a #GVariant
+ *
+ * Recurses @value and converts its contents to a #GVariant.
+ *
+ * The value must either be a simple value (integer, string, boolean,
+ * object path etc.) or a specialized container registered with
+ * dbus_g_type_get_collection(), dbus_g_type_get_map() or
+ * dbus_g_type_get_struct(). Providing any other type is a programming error
+ * (including as a child type).
+ *
+ * Returns: a new #GVariant containing @value with a floating reference
+ */
+GVariant *
+dbus_g_value_build_g_variant (const GValue *value)
+{
+  GType type;
+
+  g_return_val_if_fail (G_IS_VALUE (value), NULL);
+
+  type = G_VALUE_TYPE (value);
+
+  if (dbus_g_type_is_collection (type))
+    {
+      GVariant *variant;
+      GPtrArray *children;
+
+      children = g_ptr_array_new ();
+      dbus_g_type_collection_value_iterate (value, _collection_iterator,
+          children);
+
+      variant = g_variant_new_array (NULL, (GVariant **) children->pdata,
+          children->len);
+      g_ptr_array_free (children, TRUE);
+
+      return variant;
+    }
+  else if (dbus_g_type_is_map (type))
+    {
+      GVariant *variant;
+      GPtrArray *children;
+
+      children = g_ptr_array_new ();
+      dbus_g_type_map_value_iterate (value, _map_iterator, children);
+
+      variant = g_variant_new_array (NULL, (GVariant **) children->pdata,
+          children->len);
+      g_ptr_array_free (children, TRUE);
+
+      return variant;
+    }
+  else if (dbus_g_type_is_struct (type))
+    {
+      GVariant *variant, **children;
+      guint size, i;
+
+      size = dbus_g_type_get_struct_size (type);
+      children = g_new0 (GVariant *, size);
+
+      for (i = 0; i < size; i++)
+        {
+          GValue cvalue = { 0, };
+
+          g_value_init (&cvalue, dbus_g_type_get_struct_member_type (type, i));
+          dbus_g_type_struct_get_member (value, i, &cvalue);
+
+          children[i] = dbus_g_value_build_g_variant (&cvalue);
+          g_value_unset (&cvalue);
+        }
+
+      variant = g_variant_new_tuple (children, size);
+      g_free (children);
+
+      return variant;
+    }
+  else if (type == G_TYPE_BOOLEAN)
+    return g_variant_new_boolean (g_value_get_boolean (value));
+  else if (type == G_TYPE_UCHAR)
+    return g_variant_new_byte (g_value_get_uchar (value));
+  else if (type == G_TYPE_INT)
+    return g_variant_new_int32 (g_value_get_int (value));
+  else if (type == G_TYPE_UINT)
+    return g_variant_new_uint32 (g_value_get_uint (value));
+  else if (type == G_TYPE_INT64)
+    return g_variant_new_int64 (g_value_get_int64 (value));
+  else if (type == G_TYPE_UINT64)
+    return g_variant_new_uint64 (g_value_get_uint64 (value));
+  else if (type == G_TYPE_DOUBLE)
+    return g_variant_new_double (g_value_get_double (value));
+  else if (type == G_TYPE_STRING)
+    return g_variant_new_string (g_value_get_string (value));
+  else if (type == G_TYPE_STRV)
+    return g_variant_new_strv (g_value_get_boxed (value), -1);
+  else if (type == DBUS_TYPE_G_OBJECT_PATH)
+    return g_variant_new_object_path (g_value_get_boxed (value));
+  else if (type == DBUS_TYPE_G_SIGNATURE)
+    return g_variant_new_signature (g_value_get_boxed (value));
+  else if (type == G_TYPE_VALUE)
+    return g_variant_new_variant (
+        dbus_g_value_build_g_variant (g_value_get_boxed (value)));
+  else
+    {
+      g_error ("%s: Unknown type: %s", G_STRFUNC, g_type_name (type));
+    }
+}
diff --git a/dbus/dbus-gtype-specialized.h b/dbus/dbus-gtype-specialized.h
index 98cdde9..8c60182 100644
--- a/dbus/dbus-gtype-specialized.h
+++ b/dbus/dbus-gtype-specialized.h
@@ -169,6 +169,8 @@ const DBusGTypeSpecializedCollectionVtable* dbus_g_type_collection_peek_vtable (
 
 const DBusGTypeSpecializedStructVtable* dbus_g_type_struct_peek_vtable (GType struct_type);
 
+GVariant *dbus_g_value_build_g_variant (const GValue *value);
+
 G_END_DECLS
 
 #endif
diff --git a/dbus/examples/Makefile.am b/dbus/examples/Makefile.am
index 9178804..45dc502 100644
--- a/dbus/examples/Makefile.am
+++ b/dbus/examples/Makefile.am
@@ -8,15 +8,17 @@ INCLUDES = \
 	$(DBUS_GLIB_CFLAGS)			\
 	-DDBUS_COMPILATION
 
+LDADD = \
+	$(DBUS_GLIB_LIBS) \
+	$(top_builddir)/dbus/libdbus-glib-1.la
+
 ## Makefile.am bits for sample client/server pair
 
 noinst_PROGRAMS= example-client example-service 
 
 example_client_SOURCES= example-client.c
-example_client_LDADD= $(top_builddir)/dbus/libdbus-glib-1.la
 
 example_service_SOURCES= example-service.c
-example_service_LDADD= $(top_builddir)/dbus/libdbus-glib-1.la
 
 BUILT_SOURCES = example-service-glue.h
 
@@ -29,10 +31,8 @@ example-service-glue.h: example-service.xml
 noinst_PROGRAMS += example-signal-recipient example-signal-emitter
 
 example_signal_recipient_SOURCES= example-signal-recipient.c
-example_signal_recipient_LDADD= $(top_builddir)/dbus/libdbus-glib-1.la
 
 example_signal_emitter_SOURCES= example-signal-emitter.c
-example_signal_emitter_LDADD= $(top_builddir)/dbus/libdbus-glib-1.la
 
 BUILT_SOURCES += example-signal-emitter-glue.h
 
diff --git a/dbus/examples/statemachine/Makefile.am b/dbus/examples/statemachine/Makefile.am
index 37f0b30..2377621 100644
--- a/dbus/examples/statemachine/Makefile.am
+++ b/dbus/examples/statemachine/Makefile.am
@@ -7,6 +7,9 @@ INCLUDES = \
 	$(DBUS_GTK_THREADS_CFLAGS)		\
 	-DDBUS_COMPILATION
 
+LDADD = $(top_builddir)/dbus/libdbus-glib-1.la \
+	$(DBUS_GLIB_LIBS)
+
 ## Makefile.am bits for sample client/server pair
 
 noinst_PROGRAMS= statemachine-server
@@ -18,10 +21,9 @@ noinst_PROGRAMS= statemachine-server
 EXTRA_DIST = statemachine.h statemachine-server.h sm-marshal.list statemachine-server.xml statemachine.xml
 
 statemachine_server_SOURCES= statemachine-server.c sm-marshal.c statemachine.c
-statemachine_server_LDADD= $(top_builddir)/dbus/libdbus-glib-1.la
 
 #statemachine_client_SOURCES= statemachine-client.c sm-marshal.c statemachine.h
-#statemachine_client_LDADD= $(top_builddir)/dbus/libdbus-glib-1.la $(DBUS_GTK_THREADS_LIBS)
+#statemachine_client_LDADD= $(LDADD) $(DBUS_GTK_THREADS_LIBS)
 
 BUILT_SOURCES = statemachine-server-glue.h statemachine-glue.h
 
diff --git a/doc/reference/dbus-glib-sections.txt b/doc/reference/dbus-glib-sections.txt
index 3bdb5b8..bbee69c 100644
--- a/doc/reference/dbus-glib-sections.txt
+++ b/doc/reference/dbus-glib-sections.txt
@@ -164,6 +164,16 @@ dbus_g_type_register_map
 dbus_g_type_map_peek_vtable
 dbus_g_type_collection_peek_vtable
 dbus_g_type_register_struct
+dbus_g_value_build_g_variant
+DBUS_TYPE_G_BOOLEAN_ARRAY
+DBUS_TYPE_G_UCHAR_ARRAY
+DBUS_TYPE_G_UINT_ARRAY
+DBUS_TYPE_G_INT_ARRAY
+DBUS_TYPE_G_UINT64_ARRAY
+DBUS_TYPE_G_INT64_ARRAY
+DBUS_TYPE_G_OBJECT_ARRAY
+DBUS_TYPE_G_STRING_STRING_HASHTABLE
+DBUS_TYPE_G_SIGNATURE
 </SECTION>
 
 <SUBSECTION Private>
diff --git a/test/core/Makefile.am b/test/core/Makefile.am
index b489046..404a490 100644
--- a/test/core/Makefile.am
+++ b/test/core/Makefile.am
@@ -7,6 +7,17 @@ INCLUDES = \
 	$(DBUS_GLIB_CFLAGS)			\
 	-DDBUS_COMPILATION
 
+LDADD = \
+	$(DBUS_GLIB_THREADS_LIBS) \
+	$(DBUS_GLIB_LIBS) \
+	$(DBUS_LIBS) \
+	$(top_builddir)/dbus/libdbus-glib-1.la
+
+tool_ldadd = \
+	$(LDADD) \
+	$(DBUS_GLIB_TOOL_LIBS) \
+	$(top_builddir)/dbus/libdbus-gtool.la
+
 ## note that TESTS has special meaning (stuff to use in make check)
 ## so if adding tests not to be run in make check, don't add them to 
 ## TESTS
@@ -28,13 +39,9 @@ test_thread_server_SOURCES=				\
 	test-thread-server.c				\
 	test-thread.h
 
-test_thread_server_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/dbus/libdbus-glib-1.la 
-
 test_thread_client_SOURCES=				\
 	test-thread-client.c				\
 	test-thread.h
-
-test_thread_client_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/dbus/libdbus-glib-1.la 
 endif
 
 ## we use noinst_PROGRAMS not check_PROGRAMS for TESTS so that we
@@ -48,7 +55,8 @@ noinst_PROGRAMS = \
 	test-types \
 	test-5688 \
 	test-unregister \
-	test-variant-recursion
+	test-variant-recursion \
+	test-gvariant
 
 test_5688_SOURCES = \
 	my-object.c \
@@ -57,9 +65,6 @@ test_5688_SOURCES = \
 	my-object-subclass.h \
 	my-object-marshal.c \
 	5688.c
-test_5688_LDADD = \
-	$(top_builddir)/dbus/libdbus-glib-1.la \
-	$(DBUS_GLIB_THREADS_LIBS)
 
 test_unregister_SOURCES = \
 	my-object.c \
@@ -68,19 +73,16 @@ test_unregister_SOURCES = \
 	my-object-subclass.h \
 	my-object-marshal.c \
 	unregister.c
-test_unregister_LDADD = \
-	$(top_builddir)/dbus/libdbus-glib-1.la \
-	$(DBUS_GLIB_THREADS_LIBS)
 
 test_dbus_glib_SOURCES=				\
 	my-object-marshal.c                             \
 	test-dbus-glib.c
 
-test_dbus_glib_LDADD= $(DBUS_GLIB_TOOL_LIBS) $(top_builddir)/dbus/libdbus-glib-1.la $(top_builddir)/dbus/libdbus-gtool.la
+test_dbus_glib_LDADD= $(tool_ldadd)
 
 test_variant_recursion_SOURCES=test-variant-recursion.c
 
-test_variant_recursion_LDADD= $(DBUS_GLIB_TOOL_LIBS) $(top_builddir)/dbus/libdbus-glib-1.la $(top_builddir)/dbus/libdbus-gtool.la
+test_variant_recursion_LDADD= $(tool_ldadd)
 
 BUILT_SOURCES = test-service-glib-glue.h test-service-glib-subclass-glue.h test-service-glib-bindings.h my-object-marshal.c my-object-marshal.h 
 
@@ -91,15 +93,14 @@ test_service_glib_SOURCES=				\
 	my-object-subclass.h                    \
 	my-object-marshal.c                             \
 	test-service-glib.c 
-test_service_glib_LDADD= $(top_builddir)/dbus/libdbus-glib-1.la $(DBUS_GLIB_THREADS_LIBS) 
 
-test-service-glib-glue.h: test-service-glib.xml $(top_builddir)/dbus/dbus-binding-tool
+test-service-glib-glue.h: test-service-glib.xml $(top_builddir)/dbus/dbus-binding-tool$(EXEEXT)
 	$(DEBUG) $(DBUS_BINDING_TOOL) --prefix=my_object --mode=glib-server --output=test-service-glib-glue.h $(srcdir)/test-service-glib.xml
 
-test-service-glib-subclass-glue.h: test-service-glib-subclass.xml $(top_builddir)/dbus/dbus-binding-tool
+test-service-glib-subclass-glue.h: test-service-glib-subclass.xml $(top_builddir)/dbus/dbus-binding-tool$(EXEEXT)
 	$(DEBUG) $(DBUS_BINDING_TOOL) --prefix=my_object_subclass --mode=glib-server --output=test-service-glib-subclass-glue.h $(srcdir)/test-service-glib-subclass.xml
 
-test-service-glib-bindings.h: test-service-glib.xml $(top_builddir)/dbus/dbus-binding-tool
+test-service-glib-bindings.h: test-service-glib.xml $(top_builddir)/dbus/dbus-binding-tool$(EXEEXT)
 	$(DEBUG) $(DBUS_BINDING_TOOL) --prefix=my_object --mode=glib-client --output=test-service-glib-bindings.h $(srcdir)/test-service-glib.xml
 
 my-object-marshal.c: Makefile my-object-marshal.list
@@ -116,15 +117,15 @@ peer_server_SOURCES = \
 	my-object-subclass.h                    \
 	my-object-marshal.c                             \
 	peer-server.c
-peer_server_LDADD= $(top_builddir)/dbus/libdbus-glib-1.la $(DBUS_GLIB_THREADS_LIBS)
 
 peer_client_SOURCES = \
 	peer-client.c
-peer_client_LDADD= $(top_builddir)/dbus/libdbus-glib-1.la $(DBUS_GLIB_THREADS_LIBS)
 
 test_types_SOURCES = \
 	test-types.c
-test_types_LDADD= $(top_builddir)/dbus/libdbus-glib-1.la
+
+test_gvariant_SOURCES = \
+	test-gvariant.c
 
 CLEANFILES = \
 	$(BUILT_SOURCES) \
@@ -142,6 +143,4 @@ endif
 if HAVE_GLIB_THREADS
 test_profile_SOURCES=				\
 	test-profile.c
-
-test_profile_LDADD= $(DBUS_GLIB_THREADS_LIBS) $(top_builddir)/dbus/libdbus-glib-1.la 
 endif
diff --git a/test/core/my-object.c b/test/core/my-object.c
index 886943e..0fa8277 100644
--- a/test/core/my-object.c
+++ b/test/core/my-object.c
@@ -246,6 +246,18 @@ my_object_throw_error_multi_word (MyObject *obj, GError **error)
   return FALSE;
 }
 
+gboolean
+my_object_throw_unregistered_error (MyObject *obj, GError **error)
+{
+  /* Unregistered errors shouldn't cause a dbus abort.  See
+   * https://bugzilla.redhat.com/show_bug.cgi?id=581794
+   */
+  g_set_error (error, 0, 0,
+	       "%s",
+	       "this method always loses more");
+  return FALSE;
+}
+
 
 gboolean
 my_object_uppercase (MyObject *obj, const char *str, char **ret, GError **error)
diff --git a/test/core/my-object.h b/test/core/my-object.h
index 1d3c869..df82b66 100644
--- a/test/core/my-object.h
+++ b/test/core/my-object.h
@@ -52,6 +52,7 @@ gint32   my_object_increment_retval_error (MyObject *obj, gint32 x, GError **err
 gboolean my_object_throw_error (MyObject *obj, GError **error);
 gboolean my_object_throw_not_supported (MyObject *obj, GError **error);
 gboolean my_object_throw_error_multi_word (MyObject *obj, GError **error);
+gboolean my_object_throw_unregistered_error (MyObject *obj, GError **error);
 
 gboolean my_object_uppercase (MyObject *obj, const char *str, char **ret, GError **error);
 
diff --git a/test/core/test-dbus-glib.c b/test/core/test-dbus-glib.c
index 6de156c..0376f0d 100644
--- a/test/core/test-dbus-glib.c
+++ b/test/core/test-dbus-glib.c
@@ -796,6 +796,14 @@ main (int argc, char **argv)
   g_print ("ThrowNotSupported correctly returned error: %s\n", error->message);
   g_clear_error (&error);
 
+  g_print ("Calling ThrowUnregisteredError\n");
+  if (dbus_g_proxy_call (proxy, "ThrowUnregisteredError", &error,
+			 G_TYPE_INVALID, G_TYPE_INVALID) != FALSE)
+    lose ("ThrowError call unexpectedly succeeded!");
+
+  g_print ("ThrowUnregisteredError failed (as expected) returned error: %s\n", error->message);
+  g_clear_error (&error);
+
   g_print ("Calling IncrementRetvalError (for error)\n");
   error = NULL;
   v_UINT32_2 = 0;
diff --git a/test/core/test-gvariant.c b/test/core/test-gvariant.c
new file mode 100644
index 0000000..df6df7b
--- /dev/null
+++ b/test/core/test-gvariant.c
@@ -0,0 +1,454 @@
+#include <dbus/dbus-glib.h>
+#include <gio/gio.h>
+
+/**
+ * test_g_variant_equivalent:
+ *
+ * The function g_variant_equal() cannot be used for dictionaries because it
+ * cares about the ordering of dictionaries, which breaks our tests.
+ */
+static gboolean
+test_g_variant_equivalent (GVariant *one,
+    GVariant *two)
+{
+  if (!g_variant_type_equal (
+        g_variant_get_type (one),
+        g_variant_get_type (two)))
+    {
+      return FALSE;
+    }
+  else if (g_variant_is_of_type (one, G_VARIANT_TYPE_DICTIONARY) &&
+           g_variant_is_of_type (two, G_VARIANT_TYPE_DICTIONARY))
+    {
+      GHashTable *hash;
+      GVariantIter iter;
+      GVariant *child;
+      gboolean equal = TRUE;
+
+      if (g_variant_n_children (one) != g_variant_n_children (two))
+        return FALSE;
+
+      /* pack @one into a hash table */
+      hash = g_hash_table_new_full (g_variant_hash, g_variant_equal,
+          (GDestroyNotify) g_variant_unref, (GDestroyNotify) g_variant_unref);
+
+      g_variant_iter_init (&iter, one);
+      while ((child = g_variant_iter_next_value (&iter)))
+        {
+          g_hash_table_insert (hash,
+              g_variant_get_child_value (child, 0),
+              g_variant_get_child_value (child, 1));
+          g_variant_unref (child);
+        }
+
+      /* now iterate @two to check for the keys in @hash */
+      g_variant_iter_init (&iter, two);
+      while (equal && (child = g_variant_iter_next_value (&iter)))
+        {
+          GVariant *k, *v1, *v2;
+
+          k = g_variant_get_child_value (child, 0);
+          v1 = g_variant_get_child_value (child, 1);
+
+          v2 = g_hash_table_lookup (hash, k);
+
+          if (v2 == NULL || !test_g_variant_equivalent (v1, v2))
+            equal = FALSE;
+          else
+            g_hash_table_remove (hash, k);
+
+          g_variant_unref (k);
+          g_variant_unref (v1);
+          g_variant_unref (child);
+        }
+
+      if (g_hash_table_size (hash) > 0)
+        equal = FALSE;
+
+      g_hash_table_destroy (hash);
+
+      return equal;
+    }
+  else if (g_variant_is_container (one) &&
+           g_variant_is_container (two))
+    {
+      guint i, size;
+      gboolean equal = TRUE;
+
+      if (g_variant_n_children (one) != g_variant_n_children (two))
+        return FALSE;
+
+      size = g_variant_n_children (one);
+      for (i = 0; equal && i < size; i++)
+        {
+          GVariant *child1, *child2;
+
+          child1 = g_variant_get_child_value (one, i);
+          child2 = g_variant_get_child_value (two, i);
+
+          equal = test_g_variant_equivalent (child1, child2);
+
+          g_variant_unref (child1);
+          g_variant_unref (child2);
+        }
+
+      return equal;
+    }
+  else
+    {
+      return g_variant_equal (one, two);
+    }
+}
+
+/* test_g_variant_equivalent tests */
+static void
+test_simple_equiv (void)
+{
+  GVariant *v1, *v2;
+
+  v1 = g_variant_new_int32 (1984);
+  v2 = g_variant_new_int32 (1984);
+
+  g_assert (test_g_variant_equivalent (v1, v2));
+
+  g_variant_unref (v1);
+  g_variant_unref (v2);
+}
+
+static void
+test_simple_not_equiv (void)
+{
+  GVariant *v1, *v2;
+
+  v1 = g_variant_new_int32 (1982);
+  v2 = g_variant_new_int32 (1984);
+
+  g_assert (!test_g_variant_equivalent (v1, v2));
+
+  g_variant_unref (v1);
+  g_variant_unref (v2);
+}
+
+static void
+test_array_not_equiv (void)
+{
+  GVariantBuilder b;
+  GVariant *v1, *v2;
+
+  g_variant_builder_init (&b, G_VARIANT_TYPE ("av"));
+  g_variant_builder_add (&b, "v", g_variant_new_int32 (1984));
+  g_variant_builder_add (&b, "v", g_variant_new_string ("Orwell"));
+  g_variant_builder_add (&b, "v", g_variant_new_object_path ("/cats/escher"));
+  v1 = g_variant_builder_end (&b);
+
+  g_variant_builder_init (&b, G_VARIANT_TYPE ("av"));
+  /* note the order has changed */
+  g_variant_builder_add (&b, "v", g_variant_new_string ("Orwell"));
+  g_variant_builder_add (&b, "v", g_variant_new_int32 (1984));
+  g_variant_builder_add (&b, "v", g_variant_new_object_path ("/cats/escher"));
+  v2 = g_variant_builder_end (&b);
+
+  g_assert (!test_g_variant_equivalent (v1, v2));
+
+  g_variant_unref (v1);
+  g_variant_unref (v2);
+}
+
+static void
+test_map_equiv (void)
+{
+  GVariantBuilder b;
+  GVariant *v1, *v2;
+
+  g_variant_builder_init (&b, G_VARIANT_TYPE ("a{os}"));
+  g_variant_builder_add (&b, "{os}", "/cats/escher", "Escher Moonbeam");
+  g_variant_builder_add (&b, "{os}", "/cats/harvey", "Harvey Nomcat");
+  g_variant_builder_add (&b, "{os}", "/cats/josh", "Josh Smith");
+  v1 = g_variant_builder_end (&b);
+
+  g_variant_builder_init (&b, G_VARIANT_TYPE ("a{os}"));
+  /* note the order has changed */
+  g_variant_builder_add (&b, "{os}", "/cats/harvey", "Harvey Nomcat");
+  g_variant_builder_add (&b, "{os}", "/cats/escher", "Escher Moonbeam");
+  g_variant_builder_add (&b, "{os}", "/cats/josh", "Josh Smith");
+  v2 = g_variant_builder_end (&b);
+
+  g_assert (test_g_variant_equivalent (v1, v2));
+
+  g_variant_unref (v1);
+  g_variant_unref (v2);
+}
+
+static void
+test_map_not_equiv1 (void)
+{
+  GVariantBuilder b;
+  GVariant *v1, *v2;
+
+  g_variant_builder_init (&b, G_VARIANT_TYPE ("a{os}"));
+  g_variant_builder_add (&b, "{os}", "/cats/escher", "Escher Moonbeam");
+  g_variant_builder_add (&b, "{os}", "/cats/harvey", "Harvey Nomcat");
+  g_variant_builder_add (&b, "{os}", "/cats/josh", "Josh Smith");
+  v1 = g_variant_builder_end (&b);
+
+  g_variant_builder_init (&b, G_VARIANT_TYPE ("a{os}"));
+  g_variant_builder_add (&b, "{os}", "/cats/escher", "Escher Moonbeam");
+  g_variant_builder_add (&b, "{os}", "/cats/harvey", "Harvey Nomcat");
+  g_variant_builder_add (&b, "{os}", "/cats/josh", "Josh Smith");
+  g_variant_builder_add (&b, "{os}", "/cats/rory", "Rory Cat");
+  v2 = g_variant_builder_end (&b);
+
+  g_assert (!test_g_variant_equivalent (v1, v2));
+
+  g_variant_unref (v1);
+  g_variant_unref (v2);
+}
+
+static void
+test_map_not_equiv2 (void)
+{
+  GVariantBuilder b;
+  GVariant *v1, *v2;
+
+  g_variant_builder_init (&b, G_VARIANT_TYPE ("a{os}"));
+  g_variant_builder_add (&b, "{os}", "/cats/escher", "Escher Moonbeam");
+  g_variant_builder_add (&b, "{os}", "/cats/harvey", "Harvey Nomcat");
+  g_variant_builder_add (&b, "{os}", "/cats/josh", "Josh Smith");
+  v1 = g_variant_builder_end (&b);
+
+  g_variant_builder_init (&b, G_VARIANT_TYPE ("a{os}"));
+  g_variant_builder_add (&b, "{os}", "/cats/escher", "Escher Moonbeam");
+  g_variant_builder_add (&b, "{os}", "/cats/harvey", "Harvey Nomcat");
+  g_variant_builder_add (&b, "{os}", "/cats/josh", "Josh Cat");
+  v2 = g_variant_builder_end (&b);
+
+  g_assert (!test_g_variant_equivalent (v1, v2));
+
+  g_variant_unref (v1);
+  g_variant_unref (v2);
+}
+
+/* dbus_g_value_build_g_variant tests */
+static void
+test_i (void)
+{
+  GValue v = { 0, };
+  GVariant *var, *varc;
+
+  g_value_init (&v, G_TYPE_INT);
+  g_value_set_int (&v, 1984);
+
+  var = dbus_g_value_build_g_variant (&v);
+  g_value_unset (&v);
+
+  varc = g_variant_new_int32 (1984);
+
+  g_assert (test_g_variant_equivalent (var, varc));
+
+  g_variant_unref (var);
+  g_variant_unref (varc);
+}
+
+static void
+test_s (void)
+{
+  GValue v = { 0, };
+  GVariant *var, *varc;
+
+  g_value_init (&v, G_TYPE_STRING);
+  g_value_set_static_string (&v, "Orwell");
+
+  var = dbus_g_value_build_g_variant (&v);
+  g_value_unset (&v);
+
+  varc = g_variant_new_string ("Orwell");
+
+  g_assert (test_g_variant_equivalent (var, varc));
+
+  g_variant_unref (var);
+  g_variant_unref (varc);
+}
+
+static void
+test_o (void)
+{
+  GValue v = { 0, };
+  GVariant *var, *varc;
+
+  g_value_init (&v, DBUS_TYPE_G_OBJECT_PATH);
+  g_value_set_boxed (&v, "/cats/escher");
+
+  var = dbus_g_value_build_g_variant (&v);
+  g_value_unset (&v);
+
+  varc = g_variant_new_object_path ("/cats/escher");
+
+  g_assert (test_g_variant_equivalent (var, varc));
+
+  g_variant_unref (var);
+  g_variant_unref (varc);
+}
+
+static void
+test_us (void)
+{
+  GValue v = { 0, };
+  GVariant *var, *varc;
+  GType us = dbus_g_type_get_struct ("GValueArray",
+      G_TYPE_UINT,
+      G_TYPE_STRING,
+      G_TYPE_INVALID);
+
+  g_value_init (&v, us);
+  g_value_take_boxed (&v, dbus_g_type_specialized_construct (us));
+  dbus_g_type_struct_set (&v,
+      0, 1984,
+      1, "Orwell",
+      G_MAXUINT);
+
+  var = dbus_g_value_build_g_variant (&v);
+  g_value_unset (&v);
+
+  varc = g_variant_new ("(us)", 1984, "Orwell");
+
+  g_assert (test_g_variant_equivalent (var, varc));
+
+  g_variant_unref (var);
+  g_variant_unref (varc);
+}
+
+static void
+test_a_os (void)
+{
+  GValue v = { 0, };
+  GHashTable *map;
+  GVariantBuilder b;
+  GVariant *var, *varc;
+  GType a_os = dbus_g_type_get_map ("GHashTable",
+      DBUS_TYPE_G_OBJECT_PATH,
+      G_TYPE_STRING);
+
+  g_value_init (&v, a_os);
+  map = dbus_g_type_specialized_construct (a_os);
+
+  g_hash_table_insert (map,
+      g_strdup ("/cats/escher"), g_strdup ("Escher Moonbeam"));
+  g_hash_table_insert (map,
+      g_strdup ("/cats/harvey"), g_strdup ("Harvey Nomcat"));
+  g_hash_table_insert (map,
+      g_strdup ("/cats/josh"), g_strdup ("Josh Smith"));
+  g_value_take_boxed (&v, map);
+
+  var = dbus_g_value_build_g_variant (&v);
+  g_value_unset (&v);
+
+  g_variant_builder_init (&b, G_VARIANT_TYPE ("a{os}"));
+  g_variant_builder_add (&b, "{os}", "/cats/escher", "Escher Moonbeam");
+  g_variant_builder_add (&b, "{os}", "/cats/harvey", "Harvey Nomcat");
+  g_variant_builder_add (&b, "{os}", "/cats/josh", "Josh Smith");
+  varc = g_variant_builder_end (&b);
+
+  g_assert (test_g_variant_equivalent (var, varc));
+
+  g_variant_unref (var);
+  g_variant_unref (varc);
+}
+
+static void
+test_av (void)
+{
+  GValue v = { 0, }, *v2;
+  GVariantBuilder b;
+  GVariant *var, *varc;
+  GType av = dbus_g_type_get_collection ("GPtrArray", G_TYPE_VALUE);
+  GPtrArray *array;
+
+  g_value_init (&v, av);
+  array = dbus_g_type_specialized_construct (av);
+
+  v2 = g_new0 (GValue, 1);
+  g_value_init (v2, G_TYPE_INT);
+  g_value_set_int (v2, 1984);
+  g_ptr_array_add (array, v2);
+
+  v2 = g_new0 (GValue, 1);
+  g_value_init (v2, G_TYPE_STRING);
+  g_value_set_static_string (v2, "Orwell");
+  g_ptr_array_add (array, v2);
+
+  v2 = g_new0 (GValue, 1);
+  g_value_init (v2, DBUS_TYPE_G_OBJECT_PATH);
+  g_value_set_boxed (v2, "/cats/escher");
+  g_ptr_array_add (array, v2);
+
+  g_value_take_boxed (&v, array);
+
+  var = dbus_g_value_build_g_variant (&v);
+  g_value_unset (&v);
+
+  g_variant_builder_init (&b, G_VARIANT_TYPE ("av"));
+  g_variant_builder_add (&b, "v", g_variant_new_int32 (1984));
+  g_variant_builder_add (&b, "v", g_variant_new_string ("Orwell"));
+  g_variant_builder_add (&b, "v", g_variant_new_object_path ("/cats/escher"));
+  varc = g_variant_builder_end (&b);
+
+  g_assert (test_g_variant_equivalent (var, varc));
+
+  g_variant_unref (var);
+  g_variant_unref (varc);
+}
+
+static void
+test_g (void)
+{
+  GValue v = { 0, };
+  GVariant *var, *varc;
+
+  g_value_init (&v, DBUS_TYPE_G_SIGNATURE);
+  g_value_set_boxed (&v, "a{u(ua{sa{sv}})}");
+
+  var = dbus_g_value_build_g_variant (&v);
+  g_value_unset (&v);
+
+  varc = g_variant_new_signature ("a{u(ua{sa{sv}})}");
+
+  g_assert (test_g_variant_equivalent (var, varc));
+
+  g_variant_unref (var);
+  g_variant_unref (varc);
+}
+
+int
+main (int argc,
+    char **argv)
+{
+  g_type_init ();
+  dbus_g_type_specialized_init ();
+
+  g_test_init (&argc, &argv, NULL);
+
+  /* test_g_variant_equivalent tests */
+  g_test_add_func ("/test_g_variant_equivalent/test_simple_equiv",
+      test_simple_equiv);
+  g_test_add_func ("/test_g_variant_equivalent/test_simple_not_equiv",
+      test_simple_not_equiv);
+  g_test_add_func ("/test_g_variant_equivalent/test_array_not_equiv",
+      test_array_not_equiv);
+  g_test_add_func ("/test_g_variant_equivalent/test_map_equiv",
+      test_map_equiv);
+  g_test_add_func ("/test_g_variant_equivalent/test_map_not_equiv1",
+      test_map_not_equiv1);
+  g_test_add_func ("/test_g_variant_equivalent/test_map_not_equiv2",
+      test_map_not_equiv2);
+
+  /* dbus_g_value_build_g_variant tests */
+  g_test_add_func ("/gvalue-to-gvariant/i", test_i);
+  g_test_add_func ("/gvalue-to-gvariant/s", test_s);
+  g_test_add_func ("/gvalue-to-gvariant/o", test_o);
+  g_test_add_func ("/gvalue-to-gvariant/us", test_us);
+  g_test_add_func ("/gvalue-to-gvariant/a{os}", test_a_os);
+  g_test_add_func ("/gvalue-to-gvariant/av", test_av);
+  g_test_add_func ("/gvalue-to-gvariant/g", test_g);
+
+  return g_test_run ();
+}
diff --git a/test/core/test-profile.c b/test/core/test-profile.c
index 219c6ed..10baa0b 100644
--- a/test/core/test-profile.c
+++ b/test/core/test-profile.c
@@ -23,6 +23,14 @@
 
 #include <config.h>
 #include <glib.h>
+
+/* This test uses Unix-specific facilities */
+#ifdef G_OS_WIN32
+#define TEST_PROFILE_DISABLED
+#endif
+
+#ifndef TEST_PROFILE_DISABLED
+
 #include <dbus/dbus-glib-lowlevel.h>
 #include <stdlib.h>
 #include <unistd.h>
@@ -1090,13 +1098,15 @@ print_result (const ProfileRunVTable *vtable,
               seconds/baseline, vtable->name,
               seconds, seconds / N_ITERATIONS);
 }
+#endif
 
 int
 main (int argc, char *argv[])
 {
+#ifndef TEST_PROFILE_DISABLED
   g_thread_init (NULL);
   dbus_g_thread_init ();
-  
+
 #ifndef DBUS_DISABLE_ASSERT
   g_printerr ("You should probably --disable-asserts before you profile as they have noticeable overhead\n");
 #endif
@@ -1145,6 +1155,6 @@ main (int argc, char *argv[])
 
   /* Make valgrind happy */
   dbus_shutdown ();
-  
+#endif  /* TEST_PROFILE_DISABLED */
   return 0;
 }
diff --git a/test/core/test-service-glib.xml b/test/core/test-service-glib.xml
index 5bc94a6..3bd2de3 100644
--- a/test/core/test-service-glib.xml
+++ b/test/core/test-service-glib.xml
@@ -35,6 +35,9 @@
     <method name="ThrowErrorMultiWord">
     </method>
 
+    <method name="ThrowUnregisteredError">
+    </method>
+
     <method name="Uppercase">
       <arg type="s" direction="in" />
       <arg type="s" direction="out" />
diff --git a/test/interfaces/Makefile.am b/test/interfaces/Makefile.am
index dbdb8e1..ed5bc16 100644
--- a/test/interfaces/Makefile.am
+++ b/test/interfaces/Makefile.am
@@ -6,6 +6,10 @@ INCLUDES = \
 	$(DBUS_GLIB_CFLAGS)			\
 	-DDBUS_COMPILATION
 
+LDADD = $(DBUS_GLIB_LIBS) \
+	$(top_builddir)/dbus/libdbus-glib-1.la \
+	$(top_builddir)/dbus/libdbus-gtool.la
+
 ## note that TESTS has special meaning (stuff to use in make check)
 ## so if adding tests not to be run in make check, don't add them to 
 ## TESTS
@@ -33,13 +37,9 @@ test_service_SOURCES = \
 	test-objects.h \
 	test-server.c
 
-test_service_LDADD= $(DBUS_GLIB_TOOL_LIBS) $(top_builddir)/dbus/libdbus-glib-1.la $(top_builddir)/dbus/libdbus-gtool.la
-
 test_client_SOURCES = \
 	test-client.c
 
-test_client_LDADD= $(DBUS_GLIB_TOOL_LIBS) $(top_builddir)/dbus/libdbus-glib-1.la $(top_builddir)/dbus/libdbus-gtool.la
-
 BUILT_SOURCES = \
 	test-song-glue.h		\
 	test-hello-glue.h		\
@@ -54,34 +54,34 @@ BUILT_SOURCES = \
 	test-dup-prop-b-bindings.h \
 	test-dup-prop-b-bindings.h
 
-test-song-glue.h: test-song.xml $(top_builddir)/dbus/dbus-binding-tool
+test-song-glue.h: test-song.xml $(top_builddir)/dbus/dbus-binding-tool$(EXEEXT)
 	$(DBUS_BINDING_TOOL) --prefix=test_song --mode=glib-server --output=test-song-glue.h $(srcdir)/test-song.xml
 
-test-song-bindings.h: test-song.xml $(top_builddir)/dbus/dbus-binding-tool
+test-song-bindings.h: test-song.xml $(top_builddir)/dbus/dbus-binding-tool$(EXEEXT)
 	$(DBUS_BINDING_TOOL) --prefix=test_song --mode=glib-client --output=test-song-bindings.h $(srcdir)/test-song.xml
 
-test-hello-glue.h: test-hello.xml $(top_builddir)/dbus/dbus-binding-tool
+test-hello-glue.h: test-hello.xml $(top_builddir)/dbus/dbus-binding-tool$(EXEEXT)
 	$(DBUS_BINDING_TOOL) --prefix=test_hello --mode=glib-server --output=test-hello-glue.h $(srcdir)/test-hello.xml
 
-test-hello-bindings.h: test-hello.xml $(top_builddir)/dbus/dbus-binding-tool
+test-hello-bindings.h: test-hello.xml $(top_builddir)/dbus/dbus-binding-tool$(EXEEXT)
 	$(DBUS_BINDING_TOOL) --prefix=test_hello --mode=glib-client --output=test-hello-bindings.h $(srcdir)/test-hello.xml
 
-test-goodbye-glue.h: test-goodbye.xml $(top_builddir)/dbus/dbus-binding-tool
+test-goodbye-glue.h: test-goodbye.xml $(top_builddir)/dbus/dbus-binding-tool$(EXEEXT)
 	$(DBUS_BINDING_TOOL) --prefix=test_goodbye --mode=glib-server --output=test-goodbye-glue.h $(srcdir)/test-goodbye.xml
 
-test-goodbye-bindings.h: test-goodbye.xml $(top_builddir)/dbus/dbus-binding-tool
+test-goodbye-bindings.h: test-goodbye.xml $(top_builddir)/dbus/dbus-binding-tool$(EXEEXT)
 	$(DBUS_BINDING_TOOL) --prefix=test_goodbye --mode=glib-client --output=test-goodbye-bindings.h $(srcdir)/test-goodbye.xml
 
-test-dup-prop-a-glue.h: test-dup-prop-a.xml $(top_builddir)/dbus/dbus-binding-tool
+test-dup-prop-a-glue.h: test-dup-prop-a.xml $(top_builddir)/dbus/dbus-binding-tool$(EXEEXT)
 	$(DBUS_BINDING_TOOL) --prefix=test_dup_prop_a --mode=glib-server --output=test-dup-prop-a-glue.h $(srcdir)/test-dup-prop-a.xml
 
-test-dup-prop-a-bindings.h: test-dup-prop-a.xml $(top_builddir)/dbus/dbus-binding-tool
+test-dup-prop-a-bindings.h: test-dup-prop-a.xml $(top_builddir)/dbus/dbus-binding-tool$(EXEEXT)
 	$(DBUS_BINDING_TOOL) --prefix=test_dup_prop_a --mode=glib-client --output=test-dup-prop-a-bindings.h $(srcdir)/test-dup-prop-a.xml
 
-test-dup-prop-b-glue.h: test-dup-prop-b.xml $(top_builddir)/dbus/dbus-binding-tool
+test-dup-prop-b-glue.h: test-dup-prop-b.xml $(top_builddir)/dbus/dbus-binding-tool$(EXEEXT)
 	$(DBUS_BINDING_TOOL) --prefix=test_dup_prop_b --mode=glib-server --output=test-dup-prop-b-glue.h $(srcdir)/test-dup-prop-b.xml
 
-test-dup-prop-b-bindings.h: test-dup-prop-b.xml $(top_builddir)/dbus/dbus-binding-tool
+test-dup-prop-b-bindings.h: test-dup-prop-b.xml $(top_builddir)/dbus/dbus-binding-tool$(EXEEXT)
 	$(DBUS_BINDING_TOOL) --prefix=test_dup_prop_b --mode=glib-client --output=test-dup-prop-b-bindings.h $(srcdir)/test-dup-prop-b.xml
 
 
From 510bdcd63ae4e588a5cb72727696d5ad7fd5298b Mon Sep 17 00:00:00 2001
From: Colin Walters <walters@verbum.org>
Date: Mon, 19 Apr 2010 16:47:11 -0400
Subject: [PATCH] Respect property access flags for writing, allow disabling for reads

Because DBus-GLib originally was designed as a generic "object mapping"
binding, the handler for org.freedesktop.DBus.Properties simply
allowed access (read or write) to any GObject property that was
exported.

Later, the (compile time) introspection XML was added, and while we only
listed "exported" properties in the dynamic introspection XML, we
still allowed Get or Set calls to any property that was valid.

With this patch, we deny writes to properties which aren't listed
in the XML, or are listed as read-only.

For backwards compatibility however, we still allow reads.  A
service may disable this by calling
dbus_glib_global_set_disable_legacy_property_access().
---
 dbus/dbus-binding-tool-glib.c   |   53 +++++--
 dbus/dbus-glib.h                |    2 +
 dbus/dbus-gobject.c             |  293 +++++++++++++++++++++++++++++++++------
 test/core/my-object.c           |   63 ++++++++-
 test/core/my-object.h           |    5 +
 test/core/test-dbus-glib.c      |  252 +++++++++++++++++++++++++++++++--
 test/core/test-service-glib.xml |    5 +
 7 files changed, 601 insertions(+), 72 deletions(-)

diff --git a/dbus/dbus-binding-tool-glib.c b/dbus/dbus-binding-tool-glib.c
index 872d1f7..97545df 100644
--- a/dbus/dbus-binding-tool-glib.c
+++ b/dbus/dbus-binding-tool-glib.c
@@ -38,6 +38,10 @@
 #include <string.h>
 #include <unistd.h>
 
+/* Remember to grep for ->format_version in the code if you change this,
+ * most changes should be in dbus-gobject.c. */
+#define FORMAT_VERSION 1
+
 #define MARSHAL_PREFIX "dbus_glib_marshal_"
 
 typedef struct
@@ -466,14 +470,13 @@ generate_glue_toplevel (BaseInfo *base, DBusBindingToolCData *data, GError **err
 {
   GString *object_introspection_data_blob;
   GIOChannel *channel;
-  
+
   channel = data->channel;
-  
-  object_introspection_data_blob = g_string_new_len ("", 0);
 
+  object_introspection_data_blob = g_string_new_len ("", 0);
   data->blob = object_introspection_data_blob;
   data->count = 0;
-  
+
   data->signal_blob = g_string_new_len ("", 0);
   data->property_blob = g_string_new_len ("", 0);
 
@@ -490,10 +493,9 @@ generate_glue_toplevel (BaseInfo *base, DBusBindingToolCData *data, GError **err
   WRITE_OR_LOSE ("};\n\n");
   /* Information about the object. */
 
-  if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {\n",
-                                  channel, error, data->prefix))
+  if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {  %d,\n",
+                                  channel, error, data->prefix, FORMAT_VERSION))
     goto io_lose;
-  WRITE_OR_LOSE ("  0,\n");
   if (!write_printf_to_iochannel ("  dbus_glib_%s_methods,\n", channel, error, data->prefix))
     goto io_lose;
   if (!write_printf_to_iochannel ("  %d,\n", channel, error, data->count))
@@ -753,13 +755,36 @@ generate_glue (BaseInfo *base, DBusBindingToolCData *data, GError **error)
       for (tmp = properties; tmp != NULL; tmp = g_slist_next (tmp))
         {
           PropertyInfo *prop;
-	  
-	  prop = tmp->data;
-
-	  g_string_append (data->property_blob, interface_info_get_name (interface));
-	  g_string_append_c (data->property_blob, '\0');
-	  g_string_append (data->property_blob, property_info_get_name (prop));
-	  g_string_append_c (data->property_blob, '\0');
+          PropertyAccessFlags access_flags;
+          const char *access_string;
+          char *uscored;
+
+          prop = tmp->data;
+
+          access_flags = property_info_get_access (prop);
+          if ((access_flags & PROPERTY_READ) && (access_flags & PROPERTY_WRITE))
+            access_string = "readwrite";
+          else if (access_flags & PROPERTY_READ)
+            access_string = "read";
+          else if (access_flags & PROPERTY_WRITE)
+            access_string = "write";
+          else
+            continue;
+
+          /* We append both in the blob so we have to malloc() less when processing
+           * properties */
+          uscored = _dbus_gutils_wincaps_to_uscore (property_info_get_name (prop));
+
+          g_string_append (data->property_blob, interface_info_get_name (interface));
+          g_string_append_c (data->property_blob, '\0');
+          g_string_append (data->property_blob, property_info_get_name (prop));
+          g_string_append_c (data->property_blob, '\0');
+          g_string_append (data->property_blob, uscored);
+          g_string_append_c (data->property_blob, '\0');
+          g_string_append (data->property_blob, access_string);
+          g_string_append_c (data->property_blob, '\0');
+
+          g_free (uscored);
 	}
     }
   return TRUE;
diff --git a/dbus/dbus-glib.h b/dbus/dbus-glib.h
index 1b236d8..baf2567 100644
--- a/dbus/dbus-glib.h
+++ b/dbus/dbus-glib.h
@@ -154,6 +154,8 @@ struct _DBusGObjectInfo
   const char *exported_properties; 
 };
 
+void       dbus_glib_global_set_disable_legacy_property_access (void);
+
 void       dbus_g_object_type_install_info     (GType                 object_type,
                                                 const DBusGObjectInfo *info);
 
diff --git a/dbus/dbus-gobject.c b/dbus/dbus-gobject.c
index 6a1aba4..f340afa 100644
--- a/dbus/dbus-gobject.c
+++ b/dbus/dbus-gobject.c
@@ -37,7 +37,7 @@
 
 static char *lookup_property_name (GObject    *object,
                                    const char *wincaps_propiface,
-                                   const char *wincaps_propname);
+                                   const char *requested_propname);
 
 typedef struct
 {
@@ -46,6 +46,8 @@ typedef struct
 } DBusGErrorInfo;
 
 static GStaticRWLock globals_lock = G_STATIC_RW_LOCK_INIT;
+/* See comments in check_property_access */
+static gboolean disable_legacy_property_access = FALSE;
 static GHashTable *marshal_table = NULL;
 static GData *error_metadata = NULL;
 
@@ -83,6 +85,23 @@ uscore_to_wincaps_full (const char *uscore,
   return g_string_free (str, FALSE);
 }
 
+/* Ugly yes - but we have to accept strings from both formats */
+static gboolean
+compare_strings_ignoring_uscore_vs_dash (const char *a, const char *b)
+{
+  guint i;
+
+  for (i = 0; a[i] && b[i]; i++)
+    {
+      if ((a[i] == '-' && b[i] == '_')
+          || (a[i] == '_' && b[i] == '-'))
+        continue;
+      if (a[i] != b[i])
+        return FALSE;
+    }
+  return (a[i] == '\0') && (b[i] == '\0');
+}
+
 static char *
 uscore_to_wincaps (const char *uscore)
 {
@@ -281,7 +300,7 @@ method_output_signature_from_object_info (const DBusGObjectInfo *object,
 }
 
 static const char *
-propsig_iterate (const char *data, const char **iface, const char **name)
+signal_iterate (const char *data, const char **iface, const char **name)
 {
   *iface = data;
 
@@ -291,6 +310,108 @@ propsig_iterate (const char *data, const char **iface, const char **name)
   return string_table_next (data);
 }
 
+static const char *
+property_iterate (const char  *data,
+                  int          format_version,
+                  const char **iface,
+                  const char **exported_name,
+                  const char **name_uscored,
+                  const char **access_type)
+{
+  *iface = data;
+
+  data = string_table_next (data);
+  *exported_name = data;
+
+  data = string_table_next (data);
+  if (format_version == 1)
+    {
+      *name_uscored = data;
+      data = string_table_next (data);
+      *access_type = data;
+      return string_table_next (data);
+    }
+  else
+    {
+      /* This tells the caller they need to compute it */
+      *name_uscored = NULL;
+      /* We don't know here, however note that we will still check against the
+       * readable/writable flags from GObject's metadata.
+       */
+      *access_type = "readwrite";
+      return data;
+    }
+}
+
+/**
+ * property_info_from_object_info:
+ * @object: introspection data
+ * @interface_name: (allow-none): Expected interface name, or %NULL for any
+ * @property_name: Expected property name (can use "-" or "_" as separator)
+ * @access_type: (out): Can be one of "read", "write", "readwrite"
+ *
+ * Look up property introspection data for the given interface/name pair.
+ *
+ * Returns: %TRUE if property was found
+ */
+static gboolean
+property_info_from_object_info (const DBusGObjectInfo  *object,
+                                const char             *interface_name,
+                                const char             *property_name,
+                                const char            **access_type)
+{
+  const char *properties_iter;
+
+  properties_iter = object->exported_properties;
+  while (properties_iter != NULL && *properties_iter)
+    {
+      const char *cur_interface_name;
+      const char *cur_property_name;
+      const char *cur_uscore_property_name;
+      const char *cur_access_type;
+
+
+      properties_iter = property_iterate (properties_iter, object->format_version,
+                                          &cur_interface_name, &cur_property_name,
+                                          &cur_uscore_property_name, &cur_access_type);
+
+      if (interface_name && strcmp (interface_name, cur_interface_name) != 0)
+        continue;
+
+      /* This big pile of ugly is necessary to support the matrix resulting from multiplying
+       * (v0 data, v1 data) * (FooBar, foo-bar)
+       * In v1 data we have both forms of string, so we do a comparison against both without
+       * having to malloc.
+       * For v0 data, we need to reconstruct the foo-bar form.
+       *
+       * Adding to the complexity is that we *also* have to ignore the distinction between
+       * '-' and '_', because g_object_{get,set} does.
+       */
+      /* First, compare against the primary property name - no malloc required */
+      if (!compare_strings_ignoring_uscore_vs_dash (property_name, cur_property_name))
+        {
+          if (cur_uscore_property_name != NULL
+              && !compare_strings_ignoring_uscore_vs_dash (property_name, cur_uscore_property_name))
+            continue;
+          else
+            {
+              /* v0 metadata, construct uscore */
+              char *tmp_uscored;
+              gboolean matches;
+              tmp_uscored = _dbus_gutils_wincaps_to_uscore (cur_property_name);
+              matches = compare_strings_ignoring_uscore_vs_dash (property_name, tmp_uscored);
+              g_free (tmp_uscored);
+              if (!matches)
+                continue;
+            }
+        }
+
+      *access_type = cur_access_type;
+      return TRUE;
+    }
+  return FALSE;
+}
+
 static GQuark
 dbus_g_object_type_dbus_metadata_quark (void)
 {
@@ -578,16 +699,20 @@ write_interface (gpointer key, gpointer val, gpointer user_data)
 
   for (; properties; properties = properties->next)
     {
+      const char *iface;
       const char *propname;
+      const char *propname_uscore;
+      const char *access_type;
       GParamSpec *spec;
       char *dbus_type;
       gboolean can_set;
       gboolean can_get;
       char *s;
 
-      propname = properties->data;
       spec = NULL;
 
+      property_iterate (properties->data, object_info->format_version, &iface, &propname, &propname_uscore, &access_type);
+
       s = lookup_property_name (data->object, name, propname);
 
       spec = g_object_class_find_property (g_type_class_peek (data->gtype), s);
@@ -596,12 +721,13 @@ write_interface (gpointer key, gpointer val, gpointer user_data)
       
       dbus_type = _dbus_gtype_to_signature (G_PARAM_SPEC_VALUE_TYPE (spec));
       g_assert (dbus_type != NULL);
-      
-      can_set = ((spec->flags & G_PARAM_WRITABLE) != 0 &&
-		 (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
-      
+
+      can_set = strcmp (access_type, "readwrite") == 0
+                    && ((spec->flags & G_PARAM_WRITABLE) != 0
+                    && (spec->flags & G_PARAM_CONSTRUCT_ONLY) == 0);
+
       can_get = (spec->flags & G_PARAM_READABLE) != 0;
-      
+
       if (can_set || can_get)
 	{
 	  g_string_append_printf (xml, "    <property name=\"%s\" ", propname);
@@ -689,7 +815,7 @@ introspect_interfaces (GObject *object, GString *xml)
           const char *iface;
           const char *signame;
 
-          propsig = propsig_iterate (propsig, &iface, &signame);
+          propsig = signal_iterate (propsig, &iface, &signame);
 
           values = lookup_values (interfaces, iface);
           values->signals = g_slist_prepend (values->signals, (gpointer) signame);
@@ -700,13 +826,15 @@ introspect_interfaces (GObject *object, GString *xml)
         {
           const char *iface;
           const char *propname;
+          const char *propname_uscore;
+          const char *access_type;
 
-          propsig = propsig_iterate (propsig, &iface, &propname);
+          propsig = property_iterate (propsig, info->format_version, &iface, &propname, &propname_uscore, &access_type);
 
           values = lookup_values (interfaces, iface);
-          values->properties = g_slist_prepend (values->properties, (gpointer) propname);
+          values->properties = g_slist_prepend (values->properties, (gpointer)iface);
         }
-      
+
       memset (&data, 0, sizeof (data));
       data.xml = xml;
       data.gtype = G_TYPE_FROM_INSTANCE (object);
@@ -925,7 +1053,7 @@ dbus_g_object_type_dbus_shadow_property_quark (void)
 static char *
 lookup_property_name (GObject    *object,
                       const char *wincaps_propiface,
-                      const char *wincaps_propname)
+                      const char *requested_propname)
 {
   const DBusGObjectInfo *object_info;
   GHashTable *shadow_props;
@@ -933,9 +1061,9 @@ lookup_property_name (GObject    *object,
   GType iface_type = 0;
 
   g_assert (wincaps_propiface != NULL);
-  g_assert (wincaps_propname != NULL);
+  g_assert (requested_propname != NULL);
 
-  uscore_name = _dbus_gutils_wincaps_to_uscore (wincaps_propname);
+  uscore_name = _dbus_gutils_wincaps_to_uscore (requested_propname);
 
   object_info = lookup_object_info_by_iface (object, wincaps_propiface, FALSE, &iface_type);
   if (!object_info)
@@ -944,7 +1072,7 @@ lookup_property_name (GObject    *object,
   shadow_props = (GHashTable *) g_type_get_qdata (iface_type, SHADOW_PROP_QUARK);
   if (shadow_props)
     {
-      shadow_prop_name = g_strdup (g_hash_table_lookup (shadow_props, wincaps_propname));
+      shadow_prop_name = g_strdup (g_hash_table_lookup (shadow_props, requested_propname));
       if (shadow_prop_name)
         g_free (uscore_name);
     }
@@ -1037,24 +1165,14 @@ get_all_object_properties (DBusConnection        *connection,
     {
       const char *prop_ifname;
       const char *prop_name;
+      const char *prop_uscored;
+      const char *access_flags;
       GParamSpec *pspec;
       GType value_gtype;
       GValue value = {0, };
       gchar *variant_sig;
 
-      prop_ifname = p;
-
-      while (*p != '\0')
-        p++;
-      p++;
-      if (*p == '\0') {
-        g_warning ("malformed exported_properties in object_info");
-        break;
-      }
-      prop_name = p;
-      while (*p != '\0')
-        p++;
-      p++;
+      p = property_iterate (p, object_info->format_version, &prop_ifname, &prop_name, &prop_uscored, &access_flags);
 
       uscore_propname = lookup_property_name (object, wincaps_propiface, prop_name);
 
@@ -1729,6 +1847,70 @@ invoke_object_method (GObject         *object,
   goto done;
 }
 
+static gboolean
+check_property_access (DBusConnection  *connection,
+                       DBusMessage     *message,
+                       GObject         *object,
+                       const char      *wincaps_propiface,
+                       const char      *requested_propname,
+                       const char      *uscore_propname,
+                       gboolean         is_set)
+{
+  const DBusGObjectInfo *object_info;
+  const char *access_type;
+  DBusMessage *ret;
+
+  if (!is_set && !disable_legacy_property_access)
+    return TRUE;
+
+  object_info = lookup_object_info_by_iface (object, wincaps_propiface, TRUE, NULL);
+  if (!object_info)
+    {
+      ret = dbus_message_new_error_printf (message,
+                                           DBUS_ERROR_ACCESS_DENIED,
+                                           "Interface \"%s\" isn't exported (or may not exist), can't access property \"%s\"",
+                                           wincaps_propiface,
+                                           requested_propname);
+      dbus_connection_send (connection, ret, NULL);
+      dbus_message_unref (ret);
+      return FALSE;
+    }
+
+  /* Try both forms of property names: "foo_bar" or "FooBar"; for historical
+   * reasons we accept both.
+   */
+  if (object_info
+      && !(property_info_from_object_info (object_info, wincaps_propiface, requested_propname, &access_type)
+           || property_info_from_object_info (object_info, wincaps_propiface, uscore_propname, &access_type)))
+    {
+      ret = dbus_message_new_error_printf (message,
+                                           DBUS_ERROR_ACCESS_DENIED,
+                                           "Property \"%s\" of interface \"%s\" isn't exported (or may not exist)",
+                                           requested_propname,
+                                           wincaps_propiface);
+      dbus_connection_send (connection, ret, NULL);
+      dbus_message_unref (ret);
+      return FALSE;
+    }
+
+  if (strcmp (access_type, "readwrite") == 0)
+    return TRUE;
+  else if (is_set ? strcmp (access_type, "read") == 0
+             : strcmp (access_type, "write") == 0)
+    {
+       ret = dbus_message_new_error_printf (message,
+                                           DBUS_ERROR_ACCESS_DENIED,
+                                           "Property \"%s\" of interface \"%s\" is not %s",
+                                           requested_propname,
+                                           wincaps_propiface,
+                                           is_set ? "settable" : "readable");
+      dbus_connection_send (connection, ret, NULL);
+      dbus_message_unref (ret);
+      return FALSE;
+    }
+  return TRUE;
+}
+
 static DBusHandlerResult
 object_registration_message (DBusConnection  *connection,
                              DBusMessage     *message,
@@ -1740,7 +1922,7 @@ object_registration_message (DBusConnection  *connection,
   gboolean getter;
   gboolean getall;
   char *s;
-  const char *wincaps_propname;
+  const char *requested_propname;
   const char *wincaps_propiface;
   DBusMessageIter iter;
   const DBusGMethodInfo *method;
@@ -1762,7 +1944,8 @@ object_registration_message (DBusConnection  *connection,
     return invoke_object_method (object, object_info, method, connection, message);
 
   /* If no metainfo, we can still do properties and signals
-   * via standard GLib introspection
+   * via standard GLib introspection.  Note we do now check
+   * property access against the metainfo if available.
    */
   getter = FALSE;
   setter = FALSE;
@@ -1811,10 +1994,16 @@ object_registration_message (DBusConnection  *connection,
           g_warning ("Property get or set does not have a property name string as second arg\n");
           return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
         }
-      dbus_message_iter_get_basic (&iter, &wincaps_propname);
+      dbus_message_iter_get_basic (&iter, &requested_propname);
       dbus_message_iter_next (&iter);
 
-      s = lookup_property_name (object, wincaps_propiface, wincaps_propname);
+      s = lookup_property_name (object, wincaps_propiface, requested_propname);
+
+      if (!check_property_access (connection, message, object, wincaps_propiface, requested_propname, s, setter))
+        {
+          g_free (s);
+          return DBUS_HANDLER_RESULT_HANDLED;
+        }
 
       pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
                                             s);
@@ -1850,7 +2039,7 @@ object_registration_message (DBusConnection  *connection,
         {
           ret = dbus_message_new_error_printf (message,
                                                DBUS_ERROR_INVALID_ARGS,
-                                               "No such property %s", wincaps_propname);
+                                               "No such property %s", requested_propname);
         }
     }
 
@@ -1992,8 +2181,8 @@ export_signals (DBusGConnection *connection, const GList *info_list, GObject *ob
           GClosure *closure;
           char *s;
 
-          sigdata = propsig_iterate (sigdata, &iface, &signame);
-          
+          sigdata = signal_iterate (sigdata, &iface, &signame);
+
           s = _dbus_gutils_wincaps_to_uscore (signame);
 
           id = g_signal_lookup (s, gtype);
@@ -2167,6 +2356,28 @@ dbus_g_error_info_free (gpointer p)
  */
 
 /**
+ * dbus_glib_global_set_disable_legacy_property_access:
+ *
+ * For historical reasons, DBus-GLib will allow read-only
+ * access to every GObject property of an object exported
+ * to the bus, regardless of whether or not the property
+ * is listed in the type info installed with
+ * dbus_g_object_type_install_info().  (Write access is
+ * denied however).
+ *
+ * If you wish to restrict even read-only access, you
+ * can call this method to globally change the behavior
+ * for the entire process.
+ *
+ * Since: 0.88
+ */
+void
+dbus_glib_global_set_disable_legacy_property_access (void)
+{
+  disable_legacy_property_access = TRUE;
+}
+
+/**
  * dbus_g_object_type_install_info:
  * @object_type: #GType for the object
  * @info: introspection data generated by #dbus-glib-tool
@@ -2950,23 +3161,23 @@ _dbus_gobject_test (const char *test_data_dir)
 
   sigdata = dbus_glib_internal_test_object_info.exported_signals;
   g_assert (*sigdata != '\0');
-  sigdata = propsig_iterate (sigdata, &iface, &signame);
+  sigdata = signal_iterate (sigdata, &iface, &signame);
   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.MyObject"));
   g_assert (!strcmp (signame, "Frobnicate"));
   g_assert (*sigdata != '\0');
-  sigdata = propsig_iterate (sigdata, &iface, &signame);
+  sigdata = signal_iterate (sigdata, &iface, &signame);
   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
   g_assert (!strcmp (signame, "Sig0"));
   g_assert (*sigdata != '\0');
-  sigdata = propsig_iterate (sigdata, &iface, &signame);
+  sigdata = signal_iterate (sigdata, &iface, &signame);
   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
   g_assert (!strcmp (signame, "Sig1"));
   g_assert (*sigdata != '\0');
-  sigdata = propsig_iterate (sigdata, &iface, &signame);
+  sigdata = signal_iterate (sigdata, &iface, &signame);
   g_assert (!strcmp (iface, "org.freedesktop.DBus.Tests.FooObject"));
   g_assert (!strcmp (signame, "Sig2"));
   g_assert (*sigdata == '\0');
-  
+
 
   i = 0;
   while (i < (int) G_N_ELEMENTS (name_pairs))
diff --git a/test/core/my-object.c b/test/core/my-object.c
index 0fa8277..acb8afa 100644
--- a/test/core/my-object.c
+++ b/test/core/my-object.c
@@ -11,7 +11,10 @@
 enum
 {
   PROP_0,
-  PROP_THIS_IS_A_STRING
+  PROP_THIS_IS_A_STRING,
+  PROP_NO_TOUCHING,
+  PROP_SUPER_STUDLY,
+  PROP_SHOULD_BE_HIDDEN
 };
 
 enum
@@ -53,7 +56,19 @@ my_object_set_property (GObject      *object,
       g_free (mobject->this_is_a_string);
       mobject->this_is_a_string = g_value_dup_string (value);
       break;
-      
+
+    case PROP_NO_TOUCHING:
+      mobject->notouching = g_value_get_uint (value);
+      break;
+
+    case PROP_SUPER_STUDLY:
+      mobject->super_studly = g_value_get_double (value);
+      break;
+
+    case PROP_SHOULD_BE_HIDDEN:
+      mobject->should_be_hidden = g_value_get_boolean (value);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -75,7 +90,19 @@ my_object_get_property (GObject      *object,
     case PROP_THIS_IS_A_STRING:
       g_value_set_string (value, mobject->this_is_a_string);
       break;
-      
+
+    case PROP_NO_TOUCHING:
+      g_value_set_uint (value, mobject->notouching);
+      break;
+
+    case PROP_SUPER_STUDLY:
+      g_value_set_double (value, mobject->super_studly);
+      break;
+
+    case PROP_SHOULD_BE_HIDDEN:
+      g_value_set_boolean (value, mobject->should_be_hidden);
+      break;
+
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
       break;
@@ -86,6 +113,7 @@ static void
 my_object_init (MyObject *obj)
 {
   obj->val = 0;
+  obj->notouching = 42;
 }
 
 static void
@@ -107,6 +135,30 @@ my_object_class_init (MyObjectClass *mobject_class)
                                                         _("Example of a string property"),
                                                         "default value",
                                                         G_PARAM_READWRITE));
+  g_object_class_install_property (gobject_class,
+                                   PROP_NO_TOUCHING,
+                                   g_param_spec_uint ("no_touching",
+                                                      _("Don't touch"),
+                                                      _("Example of a readonly property (for export)"),
+                                                      0, 100, 42,
+                                                      G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                				   PROP_SUPER_STUDLY,
+				                   g_param_spec_double ("super-studly",
+                                                        _("In Studly Caps"),
+                                                        _("Example of a StudlyCaps property"),
+                                                        0, 256, 128,
+                                                        G_PARAM_READWRITE));
+
+  g_object_class_install_property (gobject_class,
+                				   PROP_SHOULD_BE_HIDDEN,
+				                   g_param_spec_boolean ("should-be-hidden",
+                                                        _("A non-exported property"),
+                                                        _("Example of a property we don't want exported"),
+                                                        FALSE,
+                                                        G_PARAM_READWRITE));
+
   signals[FROBNICATE] =
     g_signal_new ("frobnicate",
 		  G_OBJECT_CLASS_TYPE (mobject_class),
@@ -785,6 +837,11 @@ my_object_async_throw_error (MyObject *obj, DBusGMethodInvocation *context)
   g_idle_add ((GSourceFunc)do_async_error,  data);
 }
 
+void
+my_object_unsafe_disable_legacy_property_access (MyObject *obj)
+{
+  dbus_glib_global_set_disable_legacy_property_access ();
+}
 
 extern GMainLoop *loop;
 
diff --git a/test/core/my-object.h b/test/core/my-object.h
index df82b66..a93d7fd 100644
--- a/test/core/my-object.h
+++ b/test/core/my-object.h
@@ -13,7 +13,10 @@ struct MyObject
 {
   GObject parent;
   char *this_is_a_string;
+  guint notouching;
   guint val;
+  gdouble super_studly;
+  gboolean should_be_hidden;
 };
 
 struct MyObjectClass
@@ -110,4 +113,6 @@ void my_object_async_increment (MyObject *obj, gint32 x, DBusGMethodInvocation *
 
 void my_object_async_throw_error (MyObject *obj, DBusGMethodInvocation *context);
 
+void my_object_unsafe_disable_legacy_property_access (MyObject *obj);
+
 #endif
diff --git a/test/core/test-dbus-glib.c b/test/core/test-dbus-glib.c
index 0376f0d..29e0068 100644
--- a/test/core/test-dbus-glib.c
+++ b/test/core/test-dbus-glib.c
@@ -324,38 +324,48 @@ test_base_class_get_all (DBusGConnection *connection,
                             G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject",
                             G_TYPE_INVALID,
                             DBUS_TYPE_G_MAP_OF_VARIANT, &hash, G_TYPE_INVALID))
-      lose_gerror ("Unexpected error for GetProperty call of base class interface\n", error);
+      lose_gerror ("Unexpected error for GetProperty call of base class interface", error);
     g_clear_error (&error);
 
     if (!hash)
       {
         lose ("%s: Unexpected NULL hash table returned for GetAll call of base "
-              "class interface\n", object_path);
+              "class interface", object_path);
       }
 
-    if (g_hash_table_size (hash) != 1)
+    if (g_hash_table_size (hash) != 3)
       {
-        lose ("%s: Unexpected hash table size %d (expected 1) returned for GetAll "
-              " call of base class interface\n", object_path, g_hash_table_size (hash));
+        lose ("%s: Unexpected hash table size %d (expected 3) returned for GetAll "
+              " call of base class interface", object_path, g_hash_table_size (hash));
       }
     value = g_hash_table_lookup (hash, "this_is_a_string");
     if (!value)
       {
         lose ("%s: Unexpected missing 'this_is_a_string' property for GetAll "
-              "call of base class interface\n", object_path);
+              "call of base class interface", object_path);
       }
     if (!G_VALUE_HOLDS_STRING (value))
       {
         lose ("%s: Unexpected wrong type for 'this_is_a_string' property for "
-              "GetAll call of base class interface\n", object_path);
+              "GetAll call of base class interface", object_path);
       }
     foo = g_value_get_string (value);
     if (!foo || strcmp (foo, expected_string_value))
       {
         lose ("%s: Unexpected value for 'this_is_a_string' property for GetAll "
-              "call of base class interface\n", object_path);
+              "call of base class interface", object_path);
       }
 
+    value = g_hash_table_lookup (hash, "no-touching");
+    if (!value)
+      lose ("%s: Unexpected missing 'no-touching' property for GetAll "
+            "call of base class interface", object_path);
+    if (!G_VALUE_HOLDS_UINT (value))
+      lose ("%s: Unexpected wrong type for 'no-touching' property for "
+            "GetAll call of base class interface", object_path);
+    if (g_value_get_uint (value) != 42)
+      lose ("%s: Unexpected wrong value \"%d\" for 'no-touching' property for "
+            "GetAll call of base class interface", object_path, g_value_get_uint (value));
     g_hash_table_destroy (hash);
     hash = NULL;
   }
@@ -1987,9 +1997,10 @@ main (int argc, char **argv)
 	  {
 	    GSList *elt;
 	    gboolean found_manyargs;
-	    
+	    gboolean found_no_touching = FALSE;
+
 	    found_myobject = TRUE;
-	    
+
 	    found_manyargs = FALSE;
 	    for (elt = interface_info_get_methods (iface); elt; elt = elt->next)
 	      {
@@ -2004,6 +2015,23 @@ main (int argc, char **argv)
 	      }
 	    if (!found_manyargs)
 	      lose ("Missing method org.freedesktop.DBus.GLib.Tests.MyObject.ManyArgs");
+	    for (elt = interface_info_get_properties (iface); elt; elt = elt->next)
+	      {
+	        PropertyInfo *prop = elt->data;
+
+	        if (strcmp (property_info_get_name (prop), "no-touching") == 0)
+	          {
+	            if (property_info_get_access (prop) != PROPERTY_READ)
+	              lose ("property no-touching had incorrect access %d", property_info_get_access (prop));
+	            else
+	              {
+	                found_no_touching = TRUE;
+	                break;
+	              }
+	          }
+	      }
+	    if (!found_no_touching)
+	      lose ("didn't find property \"no-touching\" in org.freedesktop.DBus.GLib.Tests.MyObject");
 	  }
 	else if (!found_fooobject && strcmp (interface_info_get_name (iface), "org.freedesktop.DBus.GLib.Tests.FooObject") == 0)
 	  found_fooobject = TRUE;
@@ -2019,6 +2047,8 @@ main (int argc, char **argv)
 
   /* Properties tests */
   property_proxy = dbus_g_proxy_new_from_proxy (proxy, DBUS_INTERFACE_PROPERTIES, NULL);
+  g_object_unref (proxy);
+  proxy = NULL;
 
   g_print ("Calling GetProperty (1)\n");
   {
@@ -2047,6 +2077,48 @@ main (int argc, char **argv)
     g_value_unset (&value);
   }
 
+  g_print ("Calling GetProperty of read-only property\n");
+  {
+    GValue value = {0,};
+    if (!dbus_g_proxy_call (property_proxy, "Get", &error,
+                            G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject",
+                            G_TYPE_STRING, "no-touching",
+                            G_TYPE_INVALID,
+                            G_TYPE_VALUE, &value, G_TYPE_INVALID))
+      lose_gerror ("Failed to complete GetProperty no-touching call", error);
+    g_assert (G_VALUE_HOLDS (&value, G_TYPE_UINT));
+    g_assert (g_value_get_uint (&value) == 42);
+    g_value_unset (&value);
+  }
+
+  g_print ("Calling SetProperty (1)\n");
+  {
+    GValue value = {0,};
+    g_value_init (&value, G_TYPE_UINT);
+    g_value_set_uint (&value, 40);
+    if (dbus_g_proxy_call (property_proxy, "Set", &error,
+                           G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject",
+                           G_TYPE_STRING, "no-touching",
+                           G_TYPE_VALUE, &value, G_TYPE_INVALID, G_TYPE_INVALID))
+      lose ("Unexpected success from SetProperty call for read-only value \"no-touching\"");
+    g_clear_error (&error);
+    g_value_unset (&value);
+  }
+
+  g_print ("Calling GetProperty of read-only property (again)\n");
+  {
+    GValue value = {0,};
+    if (!dbus_g_proxy_call (property_proxy, "Get", &error,
+                            G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject",
+                            G_TYPE_STRING, "no-touching",
+                            G_TYPE_INVALID,
+                            G_TYPE_VALUE, &value, G_TYPE_INVALID))
+      lose_gerror ("Failed to complete GetProperty call", error);
+    g_assert (G_VALUE_HOLDS (&value, G_TYPE_UINT));
+    g_assert (g_value_get_uint (&value) == 42);
+    g_value_unset (&value);
+  }
+
   g_print ("Calling GetProperty (2)\n");
   {
     GValue value = {0,};
@@ -2061,7 +2133,46 @@ main (int argc, char **argv)
     g_value_unset (&value);
   }
 
-  g_print ("Calling GetProperty (3)\n");
+  g_print ("Calling GetProperty: SuperStudly\n");
+  {
+    GValue value = {0,};
+    if (!dbus_g_proxy_call (property_proxy, "Get", &error,
+                            G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject",
+                            G_TYPE_STRING, "SuperStudly",
+                            G_TYPE_INVALID,
+                            G_TYPE_VALUE, &value, G_TYPE_INVALID))
+      lose_gerror ("Failed to complete GetProperty call", error);
+    g_assert (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE));
+    g_value_unset (&value);
+  }
+
+  g_print ("Calling GetProperty: super-studly\n");
+  {
+    GValue value = {0,};
+    if (!dbus_g_proxy_call (property_proxy, "Get", &error,
+                            G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject",
+                            G_TYPE_STRING, "super-studly",
+                            G_TYPE_INVALID,
+                            G_TYPE_VALUE, &value, G_TYPE_INVALID))
+      lose_gerror ("Failed to complete GetProperty call", error);
+    g_assert (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE));
+    g_value_unset (&value);
+  }
+
+  g_print ("Calling GetProperty: super_studly\n");
+  {
+    GValue value = {0,};
+    if (!dbus_g_proxy_call (property_proxy, "Get", &error,
+                            G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject",
+                            G_TYPE_STRING, "super_studly",
+                            G_TYPE_INVALID,
+                            G_TYPE_VALUE, &value, G_TYPE_INVALID))
+      lose_gerror ("Failed to complete GetProperty call", error);
+    g_assert (G_VALUE_HOLDS (&value, G_TYPE_DOUBLE));
+    g_value_unset (&value);
+  }
+
+  g_print ("Calling GetProperty on unknown property\n");
   {
     GValue value = {0,};
     if (dbus_g_proxy_call (property_proxy, "Get", &error,
@@ -2069,13 +2180,68 @@ main (int argc, char **argv)
                             G_TYPE_STRING, "SomeUnknownProperty", 
                             G_TYPE_INVALID,
                             G_TYPE_VALUE, &value, G_TYPE_INVALID))
-      lose_gerror ("Unexpected success for GetProperty call of unknown property", error);
+      lose ("Unexpected success for GetProperty call of unknown property");
 
     g_clear_error (&error);
   }
 
-  g_object_unref (property_proxy);
-  property_proxy = NULL;
+  /* These two are expected to pass unless we call disable_legacy_property_access */
+
+  g_print ("Calling GetProperty on not-exported property (legacy enabled)\n");
+  {
+    GValue value = {0,};
+    if (!dbus_g_proxy_call (property_proxy, "Get", &error,
+                            G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject",
+                            G_TYPE_STRING, "should-be-hidden",
+                            G_TYPE_INVALID,
+                            G_TYPE_VALUE, &value, G_TYPE_INVALID))
+      lose_gerror ("Failed GetProperty call of \"should-be-hidden\" property", error);
+    g_assert (G_VALUE_HOLDS_BOOLEAN (&value));
+    g_assert (g_value_get_boolean (&value) == FALSE);
+    g_value_unset (&value);
+  }
+
+  g_print ("Calling GetProperty on not-exported property (legacy enabled)\n");
+  {
+    GValue value = {0,};
+    if (!dbus_g_proxy_call (property_proxy, "Get", &error,
+                            G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject",
+                            G_TYPE_STRING, "ShouldBeHidden",
+                            G_TYPE_INVALID,
+                            G_TYPE_VALUE, &value, G_TYPE_INVALID))
+      lose_gerror ("Failed GetProperty call of \"ShouldBeHidden\" property", error);
+
+    g_value_unset (&value);
+  }
+
+  g_print ("Calling SetProperty on not-exported property (legacy enabled)\n");
+  {
+    GValue value = {0,};
+    g_value_init (&value, G_TYPE_BOOLEAN);
+    g_value_set_boolean (&value, TRUE);
+    if (dbus_g_proxy_call (property_proxy, "Set", &error,
+                            G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject",
+                            G_TYPE_STRING, "should-be-hidden",
+                            G_TYPE_VALUE, &value,
+                            G_TYPE_INVALID, G_TYPE_INVALID))
+      lose ("Unexpected success from SetProperty call of \"should-be-hidden\" property");
+    g_value_unset (&value);
+    g_clear_error (&error);
+  }
+
+  g_print ("Calling GetProperty on not-exported property (legacy enabled)\n");
+  {
+    GValue value = {0,};
+    if (!dbus_g_proxy_call (property_proxy, "Get", &error,
+                            G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject",
+                            G_TYPE_STRING, "should-be-hidden",
+                            G_TYPE_INVALID,
+                            G_TYPE_VALUE, &value, G_TYPE_INVALID))
+      lose_gerror ("Failed GetProperty call of \"should-be-hidden\" property", error);
+    g_assert (G_VALUE_HOLDS_BOOLEAN (&value));
+    g_assert (g_value_get_boolean (&value) == FALSE);
+    g_value_unset (&value);
+  }
 
   /* Test GetAll */
   /* 'testing value' set earlier by the SetProperty tests */
@@ -2095,6 +2261,64 @@ main (int argc, char **argv)
    */
   test_subclass_get_all (connection, "/org/freedesktop/DBus/GLib/Tests/MyTestObjectSubclass");
 
+  /* Now, call disable_legacy_property_access */
+
+  g_assert (proxy == NULL);
+  proxy = dbus_g_proxy_new_for_name_owner (connection,
+                                           "org.freedesktop.DBus.GLib.TestService",
+                                           "/org/freedesktop/DBus/GLib/Tests/MyTestObject",
+                                           "org.freedesktop.DBus.GLib.Tests.MyObject",
+                                           &error);
+
+  if (!dbus_g_proxy_call (proxy, "UnsafeDisableLegacyPropertyAccess", &error,
+                          G_TYPE_INVALID, G_TYPE_INVALID))
+    lose_gerror ("Failed to invoke UnsafeDisableLegacyPropertyAccess", error);
+
+  g_object_unref (proxy);
+  proxy = NULL;
+
+  g_print ("Calling GetProperty on not-exported property (legacy *disabled*)\n");
+  {
+    GValue value = {0,};
+    if (dbus_g_proxy_call (property_proxy, "Get", &error,
+                            G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject",
+                            G_TYPE_STRING, "should-be-hidden",
+                            G_TYPE_INVALID,
+                            G_TYPE_VALUE, &value, G_TYPE_INVALID))
+      lose ("Unexpected success from GetProperty call of \"should-be-hidden\" property");
+    g_clear_error (&error);
+  }
+
+  g_print ("Calling GetProperty on not-exported property (legacy *disabled*)\n");
+  {
+    GValue value = {0,};
+    if (dbus_g_proxy_call (property_proxy, "Get", &error,
+                            G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject",
+                            G_TYPE_STRING, "ShouldBeHidden",
+                            G_TYPE_INVALID,
+                            G_TYPE_VALUE, &value, G_TYPE_INVALID))
+      lose ("Unexpected success from GetProperty call of \"ShouldBeHidden\" property");
+    g_clear_error (&error);
+  }
+
+  g_print ("Calling SetProperty on not-exported property (legacy *disabled*)\n");
+  {
+    GValue value = {0,};
+    g_value_init (&value, G_TYPE_BOOLEAN);
+    g_value_set_boolean (&value, FALSE);
+    if (dbus_g_proxy_call (property_proxy, "Set", &error,
+                            G_TYPE_STRING, "org.freedesktop.DBus.GLib.Tests.MyObject",
+                            G_TYPE_STRING, "should-be-hidden",
+                            G_TYPE_VALUE, &value,
+                            G_TYPE_INVALID, G_TYPE_INVALID))
+      lose ("Unexpected success from SetProperty call of \"should-be-hidden\" property");
+    g_value_unset (&value);
+    g_clear_error (&error);
+  }
+
+  g_object_unref (property_proxy);
+  property_proxy = NULL;
+
   test_terminate_proxy1 = dbus_g_proxy_new_for_name_owner (connection,
                             "org.freedesktop.DBus.GLib.TestService",
                             "/org/freedesktop/DBus/GLib/Tests/MyTestObject",
diff --git a/test/core/test-service-glib.xml b/test/core/test-service-glib.xml
index 3bd2de3..84a3c29 100644
--- a/test/core/test-service-glib.xml
+++ b/test/core/test-service-glib.xml
@@ -3,6 +3,8 @@
 <node name="/org/freedesktop/DBus/GLib/Tests/MyTestObject">
   <interface name="org.freedesktop.DBus.GLib.Tests.MyObject">
     <property name="this_is_a_string" type="s" access="readwrite"/>
+    <property name="no-touching" type="u" access="read"/>
+    <property name="SuperStudly" type="d" access="readwrite"/>
 
     <method name="DoNothing">
     </method>
@@ -173,6 +175,9 @@
     <method name="EmitFrobnicate">
     </method>
 
+    <method name="UnsafeDisableLegacyPropertyAccess">
+    </method>
+
     <!-- Export signals -->
     <signal name="Frobnicate"/>
 
-- 
1.7.1

diff --git a/debian/changelog b/debian/changelog
index b0e843f..938c63b 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,3 +1,28 @@
+dbus-glib (0.88-1) experimental; urgency=low
+
+  [ Sjoerd Simons ]
+  * debian/control: Move packaging from svn to git
+  * debian/rules, debian/libdbus-glib-1-2-dbg.links:
+    - Don't symlink the dbg doc directory to the main packages one, it's too
+      brittle and doesn't win much
+  * debian/control, debian/update-patches.mk
+    - Copy patch updating script from pkg-telepathy
+  * debian/patches/0001-Fix-lookup-of-regular-properties-when-shadow-propert.patch
+    - Fix crash when using shadow properties (from upstream git)
+
+  [ Simon McVittie ]
+  * New upstream version
+    - fixes CVE-2010-1172, unvalidated property access (Closes: #592753,
+      LP: #616517)
+    - drop the patch Sjoerd added, which is included in the upstream release
+    - update symbols file for new ABI (some of which is part of the security
+      bugfix)
+    - mark dbus_g_object_type_install_info as requiring a dependency on this
+      version, because it will be "version 1" instead of "version 0" object
+      info for anything compiled against this version
+
+ -- Simon McVittie <smcv@debian.org>  Mon, 16 Aug 2010 17:39:43 +0100
+
 dbus-glib (0.86-1) unstable; urgency=low
 
   * New upstream release.
diff --git a/debian/control b/debian/control
index 2dc26f1..0828eeb 100644
--- a/debian/control
+++ b/debian/control
@@ -13,8 +13,8 @@ Build-Depends: cdbs (>= 0.4.43),
                libexpat-dev,
                gtk-doc-tools (>= 1.4)
 Standards-Version: 3.8.4
-Vcs-Svn: svn://svn.debian.org/pkg-utopia/packages/unstable/dbus-glib/
-Vcs-Browser: http://svn.debian.org/wsvn/pkg-utopia/packages/unstable/dbus-glib/
+Vcs-Git: git://git.debian.org/pkg-utopia/dbus-glib.git
+Vcs-Browser: http://git.debian.org/?p=pkg-utopia/dbus-glib.git
 Homepage: http://www.freedesktop.org/wiki/Software/DBusBindings
 
 Package: libdbus-glib-1-dev
diff --git a/debian/libdbus-glib-1-2-dbg.links b/debian/libdbus-glib-1-2-dbg.links
deleted file mode 100644
index 8ea597b..0000000
--- a/debian/libdbus-glib-1-2-dbg.links
+++ /dev/null
@@ -1 +0,0 @@
-usr/share/doc/libdbus-glib-1-2 usr/share/doc/libdbus-glib-1-2-dbg
diff --git a/debian/libdbus-glib-1-2.symbols b/debian/libdbus-glib-1-2.symbols
index a9fee5a..4dd881f 100644
--- a/debian/libdbus-glib-1-2.symbols
+++ b/debian/libdbus-glib-1-2.symbols
@@ -29,7 +29,7 @@ libdbus-glib-1.so.2 libdbus-glib-1-2 #MINVER#
  dbus_g_object_path_get_g_type@Base 0.78
  dbus_g_object_register_marshaller@Base 0.78
  dbus_g_object_register_marshaller_array@Base 0.78
- dbus_g_object_type_install_info@Base 0.78
+ dbus_g_object_type_install_info@Base 0.88
  dbus_g_object_type_register_shadow_property@Base 0.86
  dbus_g_proxy_add_signal@Base 0.78
  dbus_g_proxy_begin_call@Base 0.78
@@ -85,6 +85,8 @@ libdbus-glib-1.so.2 libdbus-glib-1-2 #MINVER#
  dbus_g_type_struct_peek_vtable@Base 0.78
  dbus_g_type_struct_set@Base 0.78
  dbus_g_type_struct_set_member@Base 0.78
+ dbus_g_value_build_g_variant@Base 0.88
+ dbus_glib_global_set_disable_legacy_property_access@Base 0.88
  dbus_glib_internal_do_not_use_run_tests@Base 0.78
  dbus_message_get_g_type@Base 0.78
  dbus_server_setup_with_g_main@Base 0.78
diff --git a/debian/rules b/debian/rules
index 1f34419..5e62582 100755
--- a/debian/rules
+++ b/debian/rules
@@ -9,10 +9,8 @@ include /usr/share/cdbs/1/rules/debhelper.mk
 include /usr/share/cdbs/1/class/autotools.mk
 
 # Strict library versioning
-DEB_DH_MAKESHLIBS_ARGS_ALL := -V "libdbus-glib-1-2 (>= 0.84)"
+DEB_DH_MAKESHLIBS_ARGS_ALL := -V "libdbus-glib-1-2 (>= 0.88)"
 
 DEB_CONFIGURE_EXTRA_FLAGS := --with-introspect-xml=$(CURDIR)/debian/dbus-bus-introspect.xml
 
-# these doc directories can safely be symlinks to the library's docs
-DEB_INSTALL_DOCS_libdbus-glib-1-2-dbg := --no-act
-DEB_INSTALL_CHANGELOGS_libdbus-glib-1-2-dbg := --no-act
+include $(CURDIR)/debian/update-patches.mk
diff --git a/debian/update-patches.mk b/debian/update-patches.mk
new file mode 100644
index 0000000..55569f6
--- /dev/null
+++ b/debian/update-patches.mk
@@ -0,0 +1,10 @@
+update-patches:
+	mkdir -p $(CURDIR)/debian/patches
+	rm -f $(CURDIR)/debian/patches/*.patch
+	git format-patch -o $(CURDIR)/debian/patches debian-patches ^upstream
+	for patch in $$(ls $(CURDIR)/debian/patches/*.patch) ; \
+	do \
+		lines=$$(cat $$patch | wc -l) ; \
+		head -n $$(($$lines - 3)) $$patch > $${patch}.chomped ; \
+			mv $${patch}.chomped $$patch ; \
+	done

Attachment: signature.asc
Description: Digital signature


Reply to: