chiark / gitweb /
bus: never respond to GetManagedObjects() on sub-paths
authorDavid Herrmann <dh.herrmann@gmail.com>
Wed, 17 Sep 2014 07:28:09 +0000 (09:28 +0200)
committerDavid Herrmann <dh.herrmann@gmail.com>
Wed, 17 Sep 2014 09:01:52 +0000 (11:01 +0200)
The dbus-spec clearly specifies that GetManagedObjects() should only work
on the root-path of an object-tree. But on that path, it works regardless
whether there are any objects available or not.

We could, technically, define all sub-paths as a root-path of its own
sub-tree. However, if we do that, we enter undefined territory:

    Imagine only a fallback vtable is registered. We want
    GetManagedObjects() to *NOT* fail with UNKNOWN_METHOD if it is called
    on a valid sub-tree of the fallback. On the other hand, we don't want
    it to work on arbitrary sub-tree. Something like:
        /path/to/fallback/foobar/foobar/foobar/invalid/foobar
    should not work.
    However, there is no way to know which paths on a fallback are valid
    without looking at there registered objects. If no objects are
    registered, we have no way to figure it out.

Therefore, we now try to follow the dbus spec by only returning valid data
on registered root-paths. We treat each path as root which was registered
an object-manager on via add_object_manager(). So applications can now
directly control which paths to place an object-manager on.

We also fix the introspection to not return object-manager interfaces on
non-root paths.

Also fixes some dead-code paths initially reported by Philippe De Swert.

src/libsystemd/sd-bus/bus-objects.c

index 81c840f1294accfcb1f0a606eae02069947a88df..ecac73a94dd8fe1a1acae4470e78c464685969c7 100644 (file)
@@ -820,19 +820,6 @@ static int property_get_all_callbacks_run(
         return 1;
 }
 
         return 1;
 }
 
-static bool bus_node_with_object_manager(sd_bus *bus, struct node *n) {
-        assert(bus);
-        assert(n);
-
-        if (n->object_managers)
-                return true;
-
-        if (n->parent)
-                return bus_node_with_object_manager(bus, n->parent);
-
-        return false;
-}
-
 static bool bus_node_exists(
                 sd_bus *bus,
                 struct node *n,
 static bool bus_node_exists(
                 sd_bus *bus,
                 struct node *n,
@@ -902,7 +889,7 @@ static int process_introspect(
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
-        r = introspect_write_default_interfaces(&intro, bus_node_with_object_manager(bus, n));
+        r = introspect_write_default_interfaces(&intro, !require_fallback && n->object_managers);
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
@@ -1142,7 +1129,8 @@ static int process_get_managed_objects(
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
         _cleanup_set_free_free_ Set *s = NULL;
         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
         _cleanup_set_free_free_ Set *s = NULL;
-        bool empty;
+        Iterator i;
+        char *path;
         int r;
 
         assert(bus);
         int r;
 
         assert(bus);
@@ -1150,7 +1138,11 @@ static int process_get_managed_objects(
         assert(n);
         assert(found_object);
 
         assert(n);
         assert(found_object);
 
-        if (!bus_node_with_object_manager(bus, n))
+        /* Spec says, GetManagedObjects() is only implemented on the root of a
+         * sub-tree. Therefore, we require a registered object-manager on
+         * exactly the queried path, otherwise, we refuse to respond. */
+
+        if (require_fallback || !n->object_managers)
                 return 0;
 
         r = get_child_nodes(bus, m->path, n, &s, &error);
                 return 0;
 
         r = get_child_nodes(bus, m->path, n, &s, &error);
@@ -1167,42 +1159,13 @@ static int process_get_managed_objects(
         if (r < 0)
                 return r;
 
         if (r < 0)
                 return r;
 
-        empty = set_isempty(s);
-        if (empty) {
-                struct node_vtable *c;
-
-                /* Hmm, so we have no children? Then let's check
-                 * whether we exist at all, i.e. whether at least one
-                 * vtable exists. */
-
-                LIST_FOREACH(vtables, c, n->vtables) {
-
-                        if (require_fallback && !c->is_fallback)
-                                continue;
-
-                        if (r < 0)
-                                return r;
-                        if (r == 0)
-                                continue;
-
-                        empty = false;
-                        break;
-                }
+        SET_FOREACH(path, s, i) {
+                r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error);
+                if (r < 0)
+                        return r;
 
 
-                if (empty)
+                if (bus->nodes_modified)
                         return 0;
                         return 0;
-        } else {
-                Iterator i;
-                char *path;
-
-                SET_FOREACH(path, s, i) {
-                        r = object_manager_serialize_path_and_fallbacks(bus, reply, path, &error);
-                        if (r < 0)
-                                return r;
-
-                        if (bus->nodes_modified)
-                                return 0;
-                }
         }
 
         r = sd_bus_message_close_container(reply);
         }
 
         r = sd_bus_message_close_container(reply);