From 3e2485626368f13e3cfaa0bb5f1a89ed2ba2c725 Mon Sep 17 00:00:00 2001
From: George Kiagiadakis <george.kiagiadakis@collabora.com>
Date: Wed, 26 Jun 2019 12:11:38 +0300
Subject: [PATCH] modules: add new module to manage client permissions

Currently this will just grant full access to all clients.
A future version will refine that to grant access to specific
objects only.
---
 modules/meson.build                 |  11 +++
 modules/module-client-permissions.c | 117 ++++++++++++++++++++++++++++
 src/wireplumber.conf                |   1 +
 3 files changed, 129 insertions(+)
 create mode 100644 modules/module-client-permissions.c

diff --git a/modules/meson.build b/modules/meson.build
index 5db780e6..53ad1eef 100644
--- a/modules/meson.build
+++ b/modules/meson.build
@@ -3,6 +3,17 @@ common_c_args = [
   '-DG_LOG_USE_STRUCTURED',
 ]
 
+shared_library(
+  'wireplumber-module-client-permissions',
+  [
+    'module-client-permissions.c'
+  ],
+  c_args : [common_c_args, '-DG_LOG_DOMAIN="m-client-permissions"'],
+  install : true,
+  install_dir : wireplumber_module_dir,
+  dependencies : [wp_dep, pipewire_dep],
+)
+
 shared_library(
   'wireplumber-module-mixer',
   [
diff --git a/modules/module-client-permissions.c b/modules/module-client-permissions.c
new file mode 100644
index 00000000..b5985e8d
--- /dev/null
+++ b/modules/module-client-permissions.c
@@ -0,0 +1,117 @@
+/* WirePlumber
+ *
+ * Copyright © 2019 Collabora Ltd.
+ *    @author George Kiagiadakis <george.kiagiadakis@collabora.com>
+ *
+ * SPDX-License-Identifier: MIT
+ */
+
+#include <wp/wp.h>
+#include <pipewire/pipewire.h>
+
+struct client_data
+{
+  union {
+    struct pw_proxy *proxy;
+    struct pw_client_proxy *client_proxy;
+  };
+  struct spa_hook proxy_listener;
+  struct spa_hook client_listener;
+  gboolean done;
+};
+
+static gboolean
+do_free_client_data (gpointer data)
+{
+  g_slice_free (struct client_data, data);
+  return G_SOURCE_REMOVE;
+}
+
+static void
+proxy_destroy (void *data)
+{
+  g_idle_add (do_free_client_data, data);
+}
+
+static gboolean
+do_destroy_proxy (gpointer data)
+{
+  g_debug ("Destroying client proxy %p", data);
+  pw_proxy_destroy ((struct pw_proxy *) data);
+  return G_SOURCE_REMOVE;
+}
+
+static void
+proxy_done (void *data, int seq)
+{
+  struct client_data *d = data;
+
+  /* the proxy is not useful to keep around once we have changed permissions */
+  if (d->done)
+    g_idle_add (do_destroy_proxy, d->proxy);
+}
+
+static const struct pw_proxy_events proxy_events = {
+  PW_VERSION_PROXY_EVENTS,
+  .destroy = proxy_destroy,
+  .done = proxy_done,
+};
+
+static void
+client_info (void *object, const struct pw_client_info *info)
+{
+  struct client_data *d = object;
+  const char *access;
+
+  if (!(info->change_mask & PW_CLIENT_CHANGE_MASK_PROPS))
+    return;
+
+  g_return_if_fail (info->props);
+  access = spa_dict_lookup (info->props, "pipewire.access");
+
+  /* grant full permissions to restricted or security confined apps
+     TODO: we should eventually build a system where we can use the role
+     and the client's security label to grant access only to specific nodes
+     and endpoints in the graph */
+  if (!g_strcmp0 (access, "flatpak") || !g_strcmp0 (access, "restricted")) {
+    const struct pw_permission perm = PW_PERMISSION_INIT(-1, PW_PERM_RWX);
+
+    g_debug ("Granting full access to client %d (%p)", info->id, d->proxy);
+    pw_client_proxy_update_permissions (d->client_proxy, 1, &perm);
+  }
+
+  d->done = TRUE;
+  pw_proxy_sync (d->proxy, 123456);
+}
+
+static const struct pw_client_proxy_events client_events = {
+  PW_VERSION_CLIENT_PROXY_EVENTS,
+  .info = client_info,
+};
+
+static void
+client_added (WpRemotePipewire * remote, guint32 id, guint32 parent_id,
+    const struct spa_dict *properties, gpointer data)
+{
+  struct client_data *d;
+
+  d = g_slice_new0 (struct client_data);
+
+  d->proxy = wp_remote_pipewire_proxy_bind (remote, id,
+      PW_TYPE_INTERFACE_Client);
+  pw_proxy_add_listener (d->proxy, &d->proxy_listener, &proxy_events, d);
+  pw_client_proxy_add_listener (d->client_proxy, &d->client_listener,
+      &client_events, d);
+
+  g_debug ("Bound to client %d (%p)", id, d->proxy);
+}
+
+void
+wireplumber__module_init (WpModule * module, WpCore * core, GVariant * args)
+{
+  WpRemote *remote = wp_core_get_global (core, WP_GLOBAL_REMOTE_PIPEWIRE);
+  g_return_if_fail (remote != NULL);
+
+  g_signal_connect(remote, "global-added::client", (GCallback) client_added,
+      NULL);
+}
diff --git a/src/wireplumber.conf b/src/wireplumber.conf
index 75967301..6fb566de 100644
--- a/src/wireplumber.conf
+++ b/src/wireplumber.conf
@@ -3,3 +3,4 @@ load-module C libwireplumber-module-pw-audio-softdsp-endpoint
 load-module C libwireplumber-module-pw-alsa-udev
 load-module C libwireplumber-module-simple-policy
 load-module C libwireplumber-module-mixer
+load-module C libwireplumber-module-client-permissions
-- 
GitLab