[pulseaudio-discuss] [PATCH v3 11/11] tunnel-manager: Implement a policy that enables tunnels based on the device seat

Tanu Kaskinen tanu.kaskinen at linux.intel.com
Thu Dec 4 10:44:54 PST 2014


This allows the tunnel manager to avoid devices that belong to some
other user.

The remote-device-tunnel-enabled-condition option in
tunnel-manager.conf now supports two values, describing two different
policies for enabling a tunnel for a given remote device:

    "!device.is_monitor"
    "!device.is_monitor && (!device.seat || seats.contains(device.seat))"
---
 src/Makefile.am                             | 11 +++++--
 src/modules/tunnel-manager/remote-device.c  | 49 +++++++++++++++++++++++++++++
 src/modules/tunnel-manager/remote-device.h  |  4 +++
 src/modules/tunnel-manager/tunnel-manager.c | 16 ++++++++++
 src/modules/tunnel-manager/tunnel-manager.h |  8 +++++
 5 files changed, 86 insertions(+), 2 deletions(-)

diff --git a/src/Makefile.am b/src/Makefile.am
index 3297d5f..1ff0fcc 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1050,14 +1050,18 @@ modlibexec_LTLIBRARIES = \
 		libprotocol-cli.la \
 		libprotocol-simple.la \
 		libprotocol-http.la \
-		libprotocol-native.la \
-		libtunnel-manager.la
+		libprotocol-native.la
 
 if HAVE_SYSTEMD_LOGIN
 modlibexec_LTLIBRARIES += \
 		liblogind.la
 endif
 
+# Note the ordering: liblogind is listed first, because libtunnel-manager has
+# an optional dependency on liblogind.
+modlibexec_LTLIBRARIES += \
+		libtunnel-manager.la
+
 if HAVE_WEBRTC
 modlibexec_LTLIBRARIES += libwebrtc-util.la
 endif
@@ -1114,6 +1118,9 @@ libtunnel_manager_la_SOURCES = \
 		modules/tunnel-manager/tunnel-manager-config.c modules/tunnel-manager/tunnel-manager-config.h
 libtunnel_manager_la_LDFLAGS = $(AM_LDFLAGS) -avoid-version
 libtunnel_manager_la_LIBADD = $(AM_LIBADD) libpulsecore- at PA_MAJORMINOR@.la libpulsecommon- at PA_MAJORMINOR@.la libpulse.la
+if HAVE_SYSTEMD_LOGIN
+libtunnel_manager_la_LIBADD += liblogind.la
+endif
 
 if HAVE_ESOUND
 libprotocol_esound_la_SOURCES = pulsecore/protocol-esound.c pulsecore/protocol-esound.h pulsecore/esound.h
diff --git a/src/modules/tunnel-manager/remote-device.c b/src/modules/tunnel-manager/remote-device.c
index 137f1e1..632e368 100644
--- a/src/modules/tunnel-manager/remote-device.c
+++ b/src/modules/tunnel-manager/remote-device.c
@@ -25,6 +25,8 @@
 
 #include "remote-device.h"
 
+#include <modules/udev-util.h>
+
 #include <pulse/error.h>
 #include <pulse/introspect.h>
 
@@ -35,6 +37,18 @@
 static void tear_down_tunnel_module(pa_tunnel_manager_remote_device *device);
 static void apply_tunnel_enabled_policy(pa_tunnel_manager_remote_device *device);
 
+#ifdef HAVE_SYSTEMD_LOGIN
+static pa_hook_result_t seat_added_or_removed_cb(void *hook_data, void *call_data, void *userdata) {
+    pa_tunnel_manager_remote_device *device = userdata;
+
+    pa_assert(device);
+
+    apply_tunnel_enabled_policy(device);
+
+    return PA_HOOK_OK;
+}
+#endif
+
 void pa_tunnel_manager_remote_device_new(pa_tunnel_manager_remote_server *server, pa_device_type_t type, const void *info) {
     const char *name = NULL;
     uint32_t idx = PA_INVALID_INDEX;
@@ -122,6 +136,13 @@ void pa_tunnel_manager_remote_device_new(pa_tunnel_manager_remote_server *server
     for (i = 0; i < PA_TUNNEL_MANAGER_REMOTE_DEVICE_HOOK_MAX; i++)
         pa_hook_init(&device->hooks[i], device);
 
+#ifdef HAVE_SYSTEMD_LOGIN
+    device->seat_added_slot = pa_hook_connect(&device->server->manager->logind->hooks[PA_LOGIND_HOOK_SEAT_ADDED],
+                                                  PA_HOOK_NORMAL, seat_added_or_removed_cb, device);
+    device->seat_removed_slot = pa_hook_connect(&device->server->manager->logind->hooks[PA_LOGIND_HOOK_SEAT_REMOVED],
+                                                    PA_HOOK_NORMAL, seat_added_or_removed_cb, device);
+#endif
+
     device->can_free = true;
 
     pa_hashmap_put(server->devices, device->name, device);
@@ -216,6 +237,14 @@ void pa_tunnel_manager_remote_device_free(pa_tunnel_manager_remote_device *devic
 
     tear_down_tunnel_module(device);
 
+#ifdef HAVE_SYSTEMD_LOGIN
+    if (device->seat_removed_slot)
+        pa_hook_slot_free(device->seat_removed_slot);
+
+    if (device->seat_added_slot)
+        pa_hook_slot_free(device->seat_added_slot);
+#endif
+
     if (device->get_info_operation) {
         pa_operation_cancel(device->get_info_operation);
         pa_operation_unref(device->get_info_operation);
@@ -249,6 +278,10 @@ static void set_proplist(pa_tunnel_manager_remote_device *device, pa_proplist *p
     pa_log_debug("[%s %s] Proplist changed.", device->server->name, device->name);
 
     pa_hook_fire(&device->hooks[PA_TUNNEL_MANAGER_REMOTE_DEVICE_HOOK_PROPLIST_CHANGED], NULL);
+
+    /* Re-evaluate the tunnel enabled policy in case the udev.seat property
+     * changed. */
+    apply_tunnel_enabled_policy(device);
 }
 
 static void set_tunnel_enabled(pa_tunnel_manager_remote_device *device, bool enabled) {
@@ -349,6 +382,22 @@ static void apply_tunnel_enabled_policy(pa_tunnel_manager_remote_device *device)
         case PA_TUNNEL_MANAGER_REMOTE_DEVICE_TUNNEL_ENABLED_CONDITION_NOT_MONITOR:
             enabled = !device->is_monitor;
             break;
+
+        case PA_TUNNEL_MANAGER_REMOTE_DEVICE_TUNNEL_ENABLED_CONDITION_NOT_MONITOR_AND_SEAT_IS_OK: {
+#ifdef HAVE_SYSTEMD_LOGIN
+            const char *seat_id;
+            pa_logind_seat *seat = NULL;
+
+            seat_id = pa_proplist_gets(device->proplist, PA_PROP_UDEV_SEAT);
+            if (seat_id)
+                seat = pa_hashmap_get(device->server->manager->logind->seats, seat_id);
+
+            enabled = !device->is_monitor && (!seat_id || seat);
+#else
+            enabled = !device->is_monitor;
+#endif
+            break;
+        }
     }
 
     set_tunnel_enabled(device, enabled);
diff --git a/src/modules/tunnel-manager/remote-device.h b/src/modules/tunnel-manager/remote-device.h
index b08424c..fb813e0 100644
--- a/src/modules/tunnel-manager/remote-device.h
+++ b/src/modules/tunnel-manager/remote-device.h
@@ -45,6 +45,10 @@ struct pa_tunnel_manager_remote_device {
     pa_hook hooks[PA_TUNNEL_MANAGER_REMOTE_DEVICE_HOOK_MAX];
 
     pa_operation *get_info_operation;
+#ifdef HAVE_SYSTEMD_LOGIN
+    pa_hook_slot *seat_added_slot;
+    pa_hook_slot *seat_removed_slot;
+#endif
     pa_module *tunnel_module;
     pa_hook_slot *module_unload_slot;
 
diff --git a/src/modules/tunnel-manager/tunnel-manager.c b/src/modules/tunnel-manager/tunnel-manager.c
index be90343..ce5b407 100644
--- a/src/modules/tunnel-manager/tunnel-manager.c
+++ b/src/modules/tunnel-manager/tunnel-manager.c
@@ -36,6 +36,9 @@ const char *pa_tunnel_manager_remote_device_tunnel_enabled_condition_to_string(
     switch (condition) {
         case PA_TUNNEL_MANAGER_REMOTE_DEVICE_TUNNEL_ENABLED_CONDITION_NOT_MONITOR:
             return "!device.is_monitor";
+
+        case PA_TUNNEL_MANAGER_REMOTE_DEVICE_TUNNEL_ENABLED_CONDITION_NOT_MONITOR_AND_SEAT_IS_OK:
+            return "!device.is_monitor && (!device.seat || seats.contains(device.seat))";
     }
 
     pa_assert_not_reached();
@@ -50,6 +53,8 @@ int pa_tunnel_manager_remote_device_tunnel_enabled_condition_from_string(
 
     if (pa_streq(str, "!device.is_monitor"))
         condition = PA_TUNNEL_MANAGER_REMOTE_DEVICE_TUNNEL_ENABLED_CONDITION_NOT_MONITOR;
+    else if (pa_streq(str, "!device.is_monitor && (!device.seat || seats.contains(device.seat))"))
+        condition = PA_TUNNEL_MANAGER_REMOTE_DEVICE_TUNNEL_ENABLED_CONDITION_NOT_MONITOR_AND_SEAT_IS_OK;
     else
         return -PA_ERR_INVALID;
 
@@ -71,6 +76,9 @@ static pa_tunnel_manager *tunnel_manager_new(pa_core *core) {
     manager->remote_device_tunnel_enabled_condition = PA_TUNNEL_MANAGER_REMOTE_DEVICE_TUNNEL_ENABLED_CONDITION_NOT_MONITOR;
     manager->remote_servers = pa_hashmap_new(pa_idxset_string_hash_func, pa_idxset_string_compare_func);
     manager->refcnt = 1;
+#ifdef HAVE_SYSTEMD_LOGIN
+    manager->logind = pa_logind_get(core);
+#endif
 
     manager_config = pa_tunnel_manager_config_new();
 
@@ -114,7 +122,15 @@ static void tunnel_manager_free(pa_tunnel_manager *manager) {
 
         while ((server = pa_hashmap_first(manager->remote_servers)))
             pa_tunnel_manager_remote_server_free(server);
+    }
 
+#ifdef HAVE_SYSTEMD_LOGIN
+    if (manager->logind)
+        pa_logind_unref(manager->logind);
+#endif
+
+    if (manager->remote_servers) {
+        pa_assert(pa_hashmap_isempty(manager->remote_servers));
         pa_hashmap_free(manager->remote_servers);
     }
 
diff --git a/src/modules/tunnel-manager/tunnel-manager.h b/src/modules/tunnel-manager/tunnel-manager.h
index 75f567d..0bd3d06 100644
--- a/src/modules/tunnel-manager/tunnel-manager.h
+++ b/src/modules/tunnel-manager/tunnel-manager.h
@@ -22,6 +22,10 @@
   USA.
 ***/
 
+#ifdef HAVE_SYSTEMD_LOGIN
+#include <modules/logind/logind.h>
+#endif
+
 #include <pulsecore/core.h>
 
 #define PA_TUNNEL_MANAGER_MAX_DEVICES_PER_SERVER 50
@@ -30,6 +34,7 @@ typedef struct pa_tunnel_manager pa_tunnel_manager;
 
 typedef enum {
     PA_TUNNEL_MANAGER_REMOTE_DEVICE_TUNNEL_ENABLED_CONDITION_NOT_MONITOR,
+    PA_TUNNEL_MANAGER_REMOTE_DEVICE_TUNNEL_ENABLED_CONDITION_NOT_MONITOR_AND_SEAT_IS_OK,
 } pa_tunnel_manager_remote_device_tunnel_enabled_condition_t;
 
 const char *pa_tunnel_manager_remote_device_tunnel_enabled_condition_to_string(
@@ -43,6 +48,9 @@ struct pa_tunnel_manager {
     pa_hashmap *remote_servers; /* name -> pa_tunnel_manager_remote_server */
 
     unsigned refcnt;
+#ifdef HAVE_SYSTEMD_LOGIN
+    pa_logind *logind;
+#endif
 };
 
 /* If ref is true, the reference count of the manager is incremented, and also
-- 
1.9.3



More information about the pulseaudio-discuss mailing list