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