From d915447365be68a39607a176e03e06a05cb8a72d Mon Sep 17 00:00:00 2001 From: Olivier Fourdan Date: Tue, 18 Oct 2016 16:23:39 +0200 Subject: wayland-server: Add API to control globals visibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new API to let compositor decide whether or not a wl_global should be advertised to the clients via wl_registry_bind() or display_get_registry() By using its own filter, the compositor can decide which wl_global would be listed to clients. Compositors can use this mechanism to hide their own private interfaces that regular clients should not use. - Hiding interfaces that expose compositor implementation details makes it harder for clients to identify the compositor. Therefore clients are a little less likely to develop compositor-specific workarounds instead of reporting problems upstream. - Hiding can be used to diminish the problems from missing namespacing: if two compositors happen to use the same named global with different interfaces for their special-purpose clients, the client expecting the different interface would probably never see it advertised. Signed-off-by: Olivier Fourdan Reviewed-by: Jonas Ã…dahl Reviewed-by: Yong Bakos Acked-by: Pekka Paalanen Reviewed-by: Pekka Paalanen --- src/wayland-server-core.h | 25 ++++++++++++++++++ src/wayland-server.c | 67 +++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 87 insertions(+), 5 deletions(-) diff --git a/src/wayland-server-core.h b/src/wayland-server-core.h index 2c215e4..9ae51dc 100644 --- a/src/wayland-server-core.h +++ b/src/wayland-server-core.h @@ -28,6 +28,7 @@ #include #include +#include #include "wayland-util.h" #include "wayland-version.h" @@ -168,6 +169,30 @@ wl_global_create(struct wl_display *display, void wl_global_destroy(struct wl_global *global); +/** A filter function for wl_global objects + * + * \param client The client object + * \param global The global object to show or hide + * \param data The user data pointer + * + * A filter function enables the server to decide which globals to + * advertise to each client. + * + * When a wl_global filter is set, the given callback funtion will be + * called during wl_global advertisment and binding. + * + * This function should return true if the global object should be made + * visible to the client or false otherwise. + */ +typedef bool (*wl_display_global_filter_func_t)(const struct wl_client *client, + const struct wl_global *global, + void *data); + +void +wl_display_set_global_filter(struct wl_display *display, + wl_display_global_filter_func_t filter, + void *data); + struct wl_client * wl_client_create(struct wl_display *display, int fd); diff --git a/src/wayland-server.c b/src/wayland-server.c index 9d7d9c1..893bb56 100644 --- a/src/wayland-server.c +++ b/src/wayland-server.c @@ -101,6 +101,9 @@ struct wl_display { struct wl_signal create_client_signal; struct wl_array additional_shm_formats; + + wl_display_global_filter_func_t global_filter; + void *global_filter_data; }; struct wl_global { @@ -769,6 +772,21 @@ wl_client_destroy(struct wl_client *client) free(client); } +/* Check if a global filter is registered and use it if any. + * + * If no wl_global filter has been registered, this funtion will + * return true, allowing the wl_global to be visible to the wl_client + */ +static bool +wl_global_is_visible(const struct wl_client *client, + const struct wl_global *global) +{ + struct wl_display *display = client->display; + + return (display->global_filter == NULL || + display->global_filter(client, global, display->global_filter_data)); +} + static void registry_bind(struct wl_client *client, struct wl_resource *resource, uint32_t name, @@ -795,6 +813,10 @@ registry_bind(struct wl_client *client, WL_DISPLAY_ERROR_INVALID_OBJECT, "invalid version for global %s (%d): have %d, wanted %d", interface, name, global->version, version); + else if (!wl_global_is_visible(client, global)) + wl_resource_post_error(resource, + WL_DISPLAY_ERROR_INVALID_OBJECT, + "invalid global %s (%d)", interface, name); else global->bind(client, global->data, version, id); } @@ -850,11 +872,12 @@ display_get_registry(struct wl_client *client, ®istry_resource->link); wl_list_for_each(global, &display->global_list, link) - wl_resource_post_event(registry_resource, - WL_REGISTRY_GLOBAL, - global->name, - global->interface->name, - global->version); + if (wl_global_is_visible(client, global)) + wl_resource_post_event(registry_resource, + WL_REGISTRY_GLOBAL, + global->name, + global->interface->name, + global->version); } static const struct wl_display_interface display_interface = { @@ -925,6 +948,9 @@ wl_display_create(void) display->id = 1; display->serial = 0; + display->global_filter = NULL; + display->global_filter_data = NULL; + wl_array_init(&display->additional_shm_formats); return display; @@ -999,6 +1025,37 @@ wl_display_destroy(struct wl_display *display) free(display); } +/** Set a filter function for global objects + * + * \param display The Wayland display object. + * \param filter The global filter funtion. + * \param data User data to be associated with the global filter. + * \return None. + * + * Set a filter for the wl_display to advertise or hide global objects + * to clients. + * The set filter will be used during wl_global advertisment to + * determine whether a global object should be advertised to a + * given client, and during wl_global binding to determine whether + * a given client should be allowed to bind to a global. + * + * Clients that try to bind to a global that was filtered out will + * have an error raised. + * + * Setting the filter NULL will result in all globals being + * advertised to all clients. The default is no filter. + * + * \memberof wl_display + */ +WL_EXPORT void +wl_display_set_global_filter(struct wl_display *display, + wl_display_global_filter_func_t filter, + void *data) +{ + display->global_filter = filter; + display->global_filter_data = data; +} + WL_EXPORT struct wl_global * wl_global_create(struct wl_display *display, const struct wl_interface *interface, int version, -- cgit v1.2.3