[dbus-glib/origin/f13/master] - Apply patch to fix property access
Colin Walters
walters at fedoraproject.org
Thu Aug 12 21:44:02 UTC 2010
commit 4275e684be6573d266d50b7fb7ac313e8d049dd4
Author: Colin Walters <walters at verbum.org>
Date: Thu Aug 12 10:29:09 2010 -0400
- Apply patch to fix property access
...perty-access-flags-for-writing-allow-disa.patch | 1109 ++++++++++++++++++++
dbus-glib.spec | 8 +-
2 files changed, 1116 insertions(+), 1 deletions(-)
---
diff --git a/0001-Respect-property-access-flags-for-writing-allow-disa.patch b/0001-Respect-property-access-flags-for-writing-allow-disa.patch
new file mode 100644
index 0000000..5efc4c8
--- /dev/null
+++ b/0001-Respect-property-access-flags-for-writing-allow-disa.patch
@@ -0,0 +1,1109 @@
+From 510bdcd63ae4e588a5cb72727696d5ad7fd5298b Mon Sep 17 00:00:00 2001
+From: Colin Walters <walters at 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.2.1
+
diff --git a/dbus-glib.spec b/dbus-glib.spec
index ebf23d6..13e43bd 100644
--- a/dbus-glib.spec
+++ b/dbus-glib.spec
@@ -8,7 +8,7 @@
Summary: GLib bindings for D-Bus
Name: dbus-glib
Version: 0.86
-Release: 3%{?dist}
+Release: 4%{?dist}
URL: http://www.freedesktop.org/software/dbus/
#VCS: git:git://git.freedesktop.org/git/dbus/dbus-glib
Source0: http://dbus.freedesktop.org/releases/dbus-glib/%{name}-%{version}.tar.gz
@@ -28,6 +28,8 @@ BuildRequires: gobject-introspection-devel
# https://bugs.freedesktop.org/show_bug.cgi?id=28835
Patch0: 0001-Fix-lookup-of-regular-properties-when-shadow-propert.patch
+# https://bugzilla.redhat.com/585394
+Patch1: 0001-Respect-property-access-flags-for-writing-allow-disa.patch
%description
@@ -63,6 +65,7 @@ D-Bus tools written using the gtk+ GUI libaries
%prep
%setup -q
%patch0 -p1
+%patch1 -p1
%build
%configure --disable-tests \
@@ -125,6 +128,9 @@ rm -rf %{buildroot}
%endif
%changelog
+* Wed Aug 11 2010 Colin Walters <walters at verbum.org> - 0.86-4
+- Apply patch to fix property access
+
* Tue Jun 29 2010 Dan Williams <dcbw at redhat.com> - 0.86-3
- Fix shadow property access (fdo #28835)
More information about the scm-commits
mailing list