File dbus-1-glib-bnc628607.patch of Package dbus-1-glib

diff -urN a/dbus/dbus-binding-tool-glib.c b/dbus/dbus-binding-tool-glib.c
--- a/dbus/dbus-binding-tool-glib.c	2010-11-03 09:49:31.612224000 +0100
+++ b/dbus/dbus-binding-tool-glib.c	2010-11-03 09:49:40.137573000 +0100
@@ -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
@@ -490,10 +494,9 @@
   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))
-    goto io_lose;
-  WRITE_OR_LOSE ("  0,\n");
+      if (!write_printf_to_iochannel ("const DBusGObjectInfo dbus_glib_%s_object_info = {  %d,\n",
+                                  channel, error, data->prefix, FORMAT_VERSION))
+        goto io_lose;
   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 +756,36 @@
       for (tmp = properties; tmp != NULL; tmp = g_slist_next (tmp))
         {
           PropertyInfo *prop;
-	  
-	  prop = tmp->data;
+          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_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_free (uscored);
 	}
     }
   return TRUE;
diff -urN a/dbus/dbus-glib.h b/dbus/dbus-glib.h
--- a/dbus/dbus-glib.h	2010-11-03 09:49:31.805237000 +0100
+++ b/dbus/dbus-glib.h	2010-11-03 09:49:40.142568000 +0100
@@ -150,6 +150,8 @@
   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 -urN a/dbus/dbus-gobject.c b/dbus/dbus-gobject.c
--- a/dbus/dbus-gobject.c	2010-11-03 09:49:31.575247000 +0100
+++ b/dbus/dbus-gobject.c	2010-11-03 09:49:40.170564000 +0100
@@ -42,9 +42,28 @@
 } 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;
 
+/* 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)
 {
@@ -270,7 +289,7 @@
 }
 
 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;
 
@@ -280,6 +299,108 @@
   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)
 {
@@ -290,9 +411,14 @@
   return quark;
 }
 
+/* Iterator function should return FALSE to stop iteration, TRUE to continue */
+typedef gboolean (*ForeachObjectInfoFn) (const DBusGObjectInfo *info,
+                                         GType                 gtype,
+                                         gpointer              user_data);
+                                                                                                                                                              
 static void
 foreach_object_info (GObject *object,
-		     GFunc callback,
+                    ForeachObjectInfoFn callback,
 		     gpointer user_data)
 {
   GType *interfaces, *p;
@@ -305,7 +431,10 @@
     {
       info = g_type_get_qdata (*p, dbus_g_object_type_dbus_metadata_quark ());
       if (info != NULL && info->format_version >= 0)
-	callback ((gpointer) info, user_data);
+        {
+          if (!callback (info, *p, user_data))
+            break;
+        }
     }
 
   g_free (interfaces);
@@ -314,18 +443,23 @@
     {
       info = g_type_get_qdata (classtype, dbus_g_object_type_dbus_metadata_quark ());
       if (info != NULL && info->format_version >= 0)
-	callback ((gpointer) info, user_data);
+        {
+          if (!callback (info, classtype, user_data))
+		break;
+        }
     }
 
 }
 
-static void
-lookup_object_info_cb (gpointer data,
-		       gpointer user_data)
+static gboolean
+lookup_object_info_cb (const DBusGObjectInfo *info,
+                       GType gtype,
+                      gpointer user_data)
 {
   GList **list = (GList **) user_data;
 
-  *list = g_list_prepend (*list, data);
+  *list = g_list_prepend (*list, (gpointer) info);
+  return TRUE;
 }
 
 static GList *
@@ -340,41 +474,51 @@
 
 typedef struct {
   const char *iface;
-  DBusGObjectInfo *info;
+  const DBusGObjectInfo *info;
+  gboolean fallback;
+  GType iface_type;
 } LookupObjectInfoByIfaceData;
 
-static void
-lookup_object_info_by_iface_cb (gpointer data,
-				gpointer user_data)
+static gboolean
+lookup_object_info_by_iface_cb (const DBusGObjectInfo *info,
+                               GType gtype,
+                               gpointer user_data)
 {
-  DBusGObjectInfo *info = (DBusGObjectInfo *) data;
   LookupObjectInfoByIfaceData *lookup_data = (LookupObjectInfoByIfaceData *) user_data;
 
-  if (lookup_data->info)
-    return;
-
   /* If interface is not specified, choose the first info */
-  if (!lookup_data->iface || strlen (lookup_data->iface) == 0)
+  if (lookup_data->fallback && (!lookup_data->iface || strlen (lookup_data->iface) == 0))
     {
       lookup_data->info = info;
-      return;
+      lookup_data->iface_type = gtype;
+    }
+  else if (info->exported_properties && !strcmp (info->exported_properties, lookup_data->iface))
+    {
+      lookup_data->info = info;
+      lookup_data->iface_type = gtype;
     }
 
-  if (info->exported_properties && !strcmp (info->exported_properties, lookup_data->iface))
-    lookup_data->info = info;
+  return !lookup_data->info;
 }
 
-static DBusGObjectInfo *
+static const DBusGObjectInfo *
 lookup_object_info_by_iface (GObject     *object,
-			     const char  *iface)
+                            const char  *iface,
+                            gboolean     fallback,
+                            GType       *out_iface_type)
 {
   LookupObjectInfoByIfaceData data;
 
   data.iface = iface;
   data.info = NULL;
+  data.fallback = fallback;
+  data.iface_type = 0;
 
   foreach_object_info (object, lookup_object_info_by_iface_cb, &data);
 
+  if (out_iface_type && data.info)
+    *out_iface_type = data.iface_type;
+
   return data.info;
 }
 
@@ -498,30 +642,41 @@
 
   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;
 
-      s = _dbus_gutils_wincaps_to_uscore (propname);
+      property_iterate (properties->data, object_info->format_version, &iface, &propname, &propname_uscore, &access_type);
 
-      spec = g_object_class_find_property (g_type_class_peek (data->gtype), s);
+      if (!propname_uscore)
+        {
+          char *s = _dbus_gutils_wincaps_to_uscore (propname);
+          spec = g_object_class_find_property (g_type_class_peek (data->gtype), s);
+          g_free (s);
+        }
+      else
+        {
+          spec =  g_object_class_find_property (g_type_class_peek (data->gtype), propname_uscore);
+        }
       g_assert (spec != NULL);
-      g_free (s);
-      
+
       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);
@@ -609,7 +764,7 @@
           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);
@@ -620,13 +775,15 @@
         {
           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);
@@ -1466,6 +1623,70 @@
   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
 gobject_message_function (DBusConnection  *connection,
                           DBusMessage     *message,
@@ -1477,7 +1698,7 @@
   gboolean getter;
   gboolean getall;
   char *s;
-  const char *wincaps_propname;
+  const char *requested_propname;
   const char *wincaps_propiface;
   DBusMessageIter iter;
   const DBusGMethodInfo *method;
@@ -1497,7 +1718,8 @@
     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;
@@ -1533,7 +1755,7 @@
 
   if (getall)
     {
-      object_info = lookup_object_info_by_iface (object, wincaps_propiface);
+      object_info = lookup_object_info_by_iface (object, wincaps_propiface, TRUE, NULL);
       if (object_info != NULL)
           ret = get_all_object_properties (connection, message, object_info, object);
       else
@@ -1546,13 +1768,19 @@
           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 = _dbus_gutils_wincaps_to_uscore (wincaps_propname);
+  s = _dbus_gutils_wincaps_to_uscore (requested_propname);
 
-      pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object),
-                                            s);
+  pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (object), s);
+
+  if (!check_property_access (connection, message, object, wincaps_propiface, requested_propname, s, setter))
+    {
+      g_free (s);
+      return DBUS_HANDLER_RESULT_HANDLED;
+    }
 
       g_free (s);
 
@@ -1585,9 +1813,19 @@
         {
           ret = dbus_message_new_error_printf (message,
                                                DBUS_ERROR_INVALID_ARGS,
-                                               "No such property %s", wincaps_propname);
+                                               "No such property %s", requested_propname);
         }
     }
+  else
+    {
+      DBusMessage *ret;
+
+      ret = dbus_message_new_error_printf (message,
+                                           DBUS_ERROR_INVALID_ARGS,
+                                           "No such property %s", requested_propname);
+      dbus_connection_send (connection, ret, NULL);
+      dbus_message_unref (ret);
+    }
 
   g_assert (ret != NULL);
 
@@ -1713,8 +1951,8 @@
           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);
@@ -1888,6 +2126,32 @@
  */
 
 /**
+ * dbus_glib_global_set_disable_legacy_property_access:
+ *
+ * Historically, DBus-GLib allowed read/write access to any property
+ * regardless of the access flags specified in the introspection XML,
+ * and regardless of the DBus interface given.
+ * 
+ * As of version 0.88, DBus-GLib by default allows 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() and regardless of whether
+ * the correct interface is specified.  Write access is denied.
+ *
+ * After calling this method, it will be required that the property is
+ * exported on the given interface, and even read-only access will be
+ * checked.  This method changes behavior globally 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
@@ -2552,23 +2816,23 @@
 
   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))
openSUSE Build Service is sponsored by