From: Alessandro Astone Date: Wed, 11 Feb 2026 14:02:53 +0000 (+0100) Subject: xaccess: Rework from boolean into a list of tags X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1f7f2bc6105008add20e4c4888db69660eb563f4;p=thirdparty%2Fsystemd.git xaccess: Rework from boolean into a list of tags XDG_SESSION_EXTRA_DEVICE_ACCESS will now take a colon-separated list of identifiers. For every identifier $ID, the session is granted access to all devices tagged as "xaccess-$ID" in udev. Fixes: #40634 --- diff --git a/man/org.freedesktop.login1.xml b/man/org.freedesktop.login1.xml index cc4a146fff5..464fdab108d 100644 --- a/man/org.freedesktop.login1.xml +++ b/man/org.freedesktop.login1.xml @@ -1246,7 +1246,7 @@ node /org/freedesktop/login1/session/1 { @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s RemoteUser = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") - readonly b ExtraDeviceAccess = ...; + readonly as ExtraDeviceAccess = ['...', ...]; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") readonly s Service = '...'; @org.freedesktop.DBus.Property.EmitsChangedSignal("const") @@ -1541,9 +1541,9 @@ node /org/freedesktop/login1/session/1 { RemoteHost and RemoteUser encode the remote host and user if this is a remote session, or an empty string otherwise. - ExtraDeviceAccess encodes whether the session is granted access to additional - hardware devices, typically useful for for graphical, remote session. If true, the session is granted - access to all devices tagged with xaccess in udev. + ExtraDeviceAccess encodes the set of additional hardware devices that the session + is granted access to. For every ID in the list, the session + is granted access to all devices tagged with xaccess-ID in udev. Service encodes the PAM service name that registered the session. diff --git a/man/pam_systemd.xml b/man/pam_systemd.xml index ee3060d670e..5482ced0677 100644 --- a/man/pam_systemd.xml +++ b/man/pam_systemd.xml @@ -408,10 +408,9 @@ $XDG_SESSION_EXTRA_DEVICE_ACCESS - Whether or not the session shall be granted additional hardware device access, - typically useful for graphical, remote session. If true, the session is granted access to all - devices tagged with xaccess in udev. Typically, rendering device nodes of - the GPU are tagged like this. + The set of additional hardware devices that the session shall be granted access to. + For every ID in the list, the session is granted + access to all devices tagged with xaccess-ID in udev. diff --git a/man/rules/meson.build b/man/rules/meson.build index 606cb72d294..9eae3e8249f 100644 --- a/man/rules/meson.build +++ b/man/rules/meson.build @@ -926,7 +926,7 @@ manpages = [ 'sd_session_get_uid', 'sd_session_get_username', 'sd_session_get_vt', - 'sd_session_has_extra_device_access', + 'sd_session_get_extra_device_access', 'sd_session_is_remote'], 'HAVE_PAM'], ['sd_uid_get_state', diff --git a/man/sd-login.xml b/man/sd-login.xml index 47ea4680b63..6c8745d358a 100644 --- a/man/sd-login.xml +++ b/man/sd-login.xml @@ -191,12 +191,13 @@ - Tag xaccess + Tag xaccess-* - When set, access to this device is granted to sessions - created with ExtraDeviceAccess. This is typically useful - for graphical, remote sessions. As the ExtraDeviceAccess - sessions open and close, access to the device is updated accordingly. + When xaccess-ID + is set, access to this device is granted to sessions created with + ID listed in ExtraDeviceAccess. + As the sessions with some ExtraDeviceAccess open and close, + access to the device is updated accordingly. diff --git a/man/sd_session_is_active.xml b/man/sd_session_is_active.xml index 3a3935cfef8..f1c26611850 100644 --- a/man/sd_session_is_active.xml +++ b/man/sd_session_is_active.xml @@ -34,7 +34,7 @@ sd_session_get_remote_host sd_session_get_remote_user sd_session_get_leader - sd_session_has_extra_device_access + sd_session_get_extra_device_access Determine state of a specific session @@ -143,8 +143,9 @@ - int sd_session_has_extra_device_access + int sd_session_get_extra_device_access const char *session + char ***ret_ids @@ -280,11 +281,11 @@ session identifier. This function will return an error if the seat does not support VTs. - sd_session_has_extra_device_access() may - be used to determine whether the session is granted access to - additional hardware devices, typically useful for for graphical, - remote session. If true, the session is granted access to all - devices tagged with xaccess in udev. + sd_session_get_extra_device_access() may + be used to determine which additional hardware devices the session + is granted access to. For every ID + in the list, the session is granted access to all devices tagged with + xaccess-ID in udev. If the session parameter of any of these functions is passed as NULL, the operation is @@ -296,9 +297,8 @@ Return Value If the test succeeds, - sd_session_is_active(), - sd_session_is_remote(), and - sd_session_has_extra_device_access() + sd_session_is_active() and + sd_session_is_remote() return a positive integer; if it fails, 0. On success, sd_session_get_state(), sd_session_get_uid(), @@ -310,9 +310,10 @@ sd_session_get_display(), sd_session_get_leader(), sd_session_get_remote_user(), - sd_session_get_remote_host() and - sd_session_get_tty() return 0 or - a positive integer. On failure, these calls return a + sd_session_get_remote_host(), + sd_session_get_tty(), and + sd_session_get_extra_device_access() + return 0 or a positive integer. On failure, these calls return a negative errno-style error code. @@ -366,7 +367,7 @@ sd_session_get_username(), sd_session_get_start_time(), and sd_session_get_leader() were added in version 254. - sd_session_has_extra_device_access() was added in version 260. + sd_session_get_extra_device_access() was added in version 260. diff --git a/src/libsystemd/libsystemd.sym b/src/libsystemd/libsystemd.sym index 735aa782142..aa270a483a4 100644 --- a/src/libsystemd/libsystemd.sym +++ b/src/libsystemd/libsystemd.sym @@ -1088,5 +1088,5 @@ global: LIBSYSTEMD_260 { global: - sd_session_has_extra_device_access; + sd_session_get_extra_device_access; } LIBSYSTEMD_259; diff --git a/src/libsystemd/sd-json/json-util.h b/src/libsystemd/sd-json/json-util.h index 5365eedcae5..d06a72aef9a 100644 --- a/src/libsystemd/sd-json/json-util.h +++ b/src/libsystemd/sd-json/json-util.h @@ -264,6 +264,8 @@ enum { SD_JSON_BUILD_PAIR_CONDITION(condition, name, SD_JSON_BUILD_UNSIGNED(value)) #define JSON_BUILD_PAIR_CONDITION_BOOLEAN(condition, name, value) \ SD_JSON_BUILD_PAIR_CONDITION(condition, name, SD_JSON_BUILD_BOOLEAN(value)) +#define JSON_BUILD_PAIR_CONDITION_STRV(condition, name, value) \ + SD_JSON_BUILD_PAIR_CONDITION(condition, name, SD_JSON_BUILD_STRV(value)) int json_variant_new_pidref(sd_json_variant **ret, PidRef *pidref); int json_variant_new_devnum(sd_json_variant **ret, dev_t devnum); diff --git a/src/libsystemd/sd-login/sd-login.c b/src/libsystemd/sd-login/sd-login.c index bf214ab661b..1331190c2e3 100644 --- a/src/libsystemd/sd-login/sd-login.c +++ b/src/libsystemd/sd-login/sd-login.c @@ -677,7 +677,7 @@ _public_ int sd_session_is_remote(const char *session) { return parse_boolean(s); } -_public_ int sd_session_has_extra_device_access(const char *session) { +_public_ int sd_session_get_extra_device_access(const char *session, char ***ret_ids) { _cleanup_free_ char *p = NULL, *s = NULL; int r; @@ -690,10 +690,21 @@ _public_ int sd_session_has_extra_device_access(const char *session) { return -ENXIO; if (r < 0) return r; - if (isempty(s)) - return -ENODATA; - return parse_boolean(s); + _cleanup_strv_free_ char **ids = NULL; + size_t n_ids = 0; + if (!isempty(s)) { + ids = strv_split(s, /* separators= */ NULL); + if (!ids) + return -ENOMEM; + + n_ids = strv_length(ids); + } + + if (ret_ids) + *ret_ids = TAKE_PTR(ids); + + return n_ids; } _public_ int sd_session_get_state(const char *session, char **ret_state) { diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 8ccaa9a1cd4..87cc4f14bc8 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -898,7 +898,7 @@ int manager_create_session( bool remote, const char *remote_user, const char *remote_host, - bool extra_device_access, + char * const *extra_device_access, Session **ret_session) { bool mangle_class = false; @@ -1005,7 +1005,6 @@ int manager_create_session( session->original_type = session->type = type; session->remote = remote; - session->extra_device_access = extra_device_access; session->vtnr = vtnr; session->class = class; @@ -1055,6 +1054,10 @@ int manager_create_session( goto fail; } + r = strv_copy_unless_empty(extra_device_access, &session->extra_device_access); + if (r < 0) + goto fail; + if (seat) { r = seat_attach_session(seat, session); if (r < 0) @@ -1229,7 +1232,7 @@ static int manager_create_session_by_bus( remote, remote_user, remote_host, - /* extra_device_access= */ false, + /* extra_device_access= */ NULL, &session); if (r == -EBUSY) return sd_bus_error_set(error, BUS_ERROR_SESSION_BUSY, "Already running in a session or user slice"); diff --git a/src/login/logind-dbus.h b/src/login/logind-dbus.h index e254e62195e..1ece1c68c8c 100644 --- a/src/login/logind-dbus.h +++ b/src/login/logind-dbus.h @@ -57,7 +57,7 @@ int manager_create_session( bool remote, const char *remote_user, const char *remote_host, - bool extra_device_access, + char * const *extra_device_access, Session **ret_session); extern const BusObjectImplementation manager_object; diff --git a/src/login/logind-session-dbus.c b/src/login/logind-session-dbus.c index 21d16dbd8d8..4da9bb24255 100644 --- a/src/login/logind-session-dbus.c +++ b/src/login/logind-session-dbus.c @@ -985,7 +985,7 @@ static const sd_bus_vtable session_vtable[] = { SD_BUS_PROPERTY("Remote", "b", bus_property_get_bool, offsetof(Session, remote), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RemoteHost", "s", NULL, offsetof(Session, remote_host), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("RemoteUser", "s", NULL, offsetof(Session, remote_user), SD_BUS_VTABLE_PROPERTY_CONST), - SD_BUS_PROPERTY("ExtraDeviceAccess", "b", bus_property_get_bool, offsetof(Session, extra_device_access), SD_BUS_VTABLE_PROPERTY_CONST), + SD_BUS_PROPERTY("ExtraDeviceAccess", "as", NULL, offsetof(Session, extra_device_access), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Session, service), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Desktop", "s", NULL, offsetof(Session, desktop), SD_BUS_VTABLE_PROPERTY_CONST), SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Session, scope), SD_BUS_VTABLE_PROPERTY_CONST), diff --git a/src/login/logind-session.c b/src/login/logind-session.c index 2b2c36b1d46..72cad136650 100644 --- a/src/login/logind-session.c +++ b/src/login/logind-session.c @@ -45,6 +45,7 @@ #include "process-util.h" #include "serialize.h" #include "string-table.h" +#include "strv.h" #include "terminal-util.h" #include "tmpfile-util.h" #include "user-record.h" @@ -210,6 +211,7 @@ Session* session_free(Session *s) { free(s->remote_user); free(s->service); free(s->desktop); + strv_free(s->extra_device_access); hashmap_remove(s->manager->sessions, s->id); @@ -278,24 +280,37 @@ static void session_save_devices(Session *s, FILE *f) { } } -static int trigger_xaccess(void) { +static int trigger_xaccess(char * const *extra_devices) { int r; - _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; - r = sd_device_enumerator_new(&e); + if (strv_isempty(extra_devices)) + return 0; + + _cleanup_strv_free_ char **tags = NULL; + r = strv_extend_strv_biconcat(&tags, "xaccess-", (const char * const *)extra_devices, /* suffix= */ NULL); if (r < 0) return r; - r = sd_device_enumerator_add_match_tag(e, "xaccess"); + _cleanup_(sd_device_enumerator_unrefp) sd_device_enumerator *e = NULL; + r = sd_device_enumerator_new(&e); if (r < 0) return r; - FOREACH_DEVICE(e, d) { - /* Verify that the tag is still in place. */ - r = sd_device_has_current_tag(d, "xaccess"); + STRV_FOREACH(tag, tags) { + r = sd_device_enumerator_add_match_tag(e, *tag); if (r < 0) return r; - if (r == 0) + } + + FOREACH_DEVICE(e, d) { + /* Verify that the tag is still in place. */ + bool has_xaccess = false; + STRV_FOREACH(tag, tags) + if (sd_device_has_current_tag(d, *tag)) { + has_xaccess = true; + break; + } + if (!has_xaccess) continue; /* In case people mistag devices without nodes, we need to ignore this. */ @@ -349,14 +364,12 @@ int session_save(Session *s) { "IS_DISPLAY=%s\n" "STATE=%s\n" "REMOTE=%s\n" - "EXTRA_DEVICE_ACCESS=%s\n" "LEADER_FD_SAVED=%s\n", s->user->user_record->uid, one_zero(session_is_active(s)), one_zero(s->user->display == s), session_state_to_string(session_get_state(s)), one_zero(s->remote), - one_zero(s->extra_device_access), one_zero(s->leader_fd_saved)); env_file_fputs_assignment(f, "USER=", s->user->user_record->user_name); @@ -414,6 +427,13 @@ int session_save(Session *s) { session_save_devices(s, f); } + if (s->extra_device_access) { + _cleanup_free_ char *extra_devices = strv_join(s->extra_device_access, " "); + if (!extra_devices) + return log_oom(); + fprintf(f, "EXTRA_DEVICE_ACCESS=%s\n", extra_devices); + } + r = flink_tmpfile(f, temp_path, s->state_file, LINK_TMPFILE_REPLACE); if (r < 0) return log_error_errno(r, "Failed to move '%s' into place: %m", s->state_file); @@ -586,9 +606,9 @@ int session_load(Session *s) { } if (extra_device_access) { - k = parse_boolean(extra_device_access); - if (k >= 0) - s->extra_device_access = k; + s->extra_device_access = strv_split(extra_device_access, /* separators= */ NULL); + if (!s->extra_device_access) + return log_oom(); } if (vtnr) @@ -915,8 +935,7 @@ int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error) { if (s->seat) (void) seat_save(s->seat); - if (s->extra_device_access) - (void) trigger_xaccess(); + (void) trigger_xaccess(s->extra_device_access); /* Send signals */ (void) session_send_signal(s, true); @@ -1008,8 +1027,7 @@ int session_stop(Session *s, bool force) { (void) session_save(s); (void) user_save(s->user); - if (s->extra_device_access) - (void) trigger_xaccess(); + (void) trigger_xaccess(s->extra_device_access); return r; } diff --git a/src/login/logind-session.h b/src/login/logind-session.h index ddebd43e55d..f51eed24fa0 100644 --- a/src/login/logind-session.h +++ b/src/login/logind-session.h @@ -121,7 +121,7 @@ typedef struct Session { char *remote_host; char *service; char *desktop; - bool extra_device_access; + char **extra_device_access; char *scope; char *scope_job; diff --git a/src/login/logind-varlink.c b/src/login/logind-varlink.c index 0016f276f37..a1fdac01c90 100644 --- a/src/login/logind-varlink.c +++ b/src/login/logind-varlink.c @@ -15,6 +15,7 @@ #include "logind-seat.h" #include "logind-user.h" #include "logind-varlink.h" +#include "strv.h" #include "terminal-util.h" #include "user-record.h" #include "user-util.h" @@ -145,11 +146,12 @@ typedef struct CreateSessionParameters { int remote; const char *remote_user; const char *remote_host; - bool extra_device_access; + char **extra_device_access; } CreateSessionParameters; static void create_session_parameters_done(CreateSessionParameters *p) { pidref_done(&p->pid); + strv_free(p->extra_device_access); } static int vl_method_create_session(sd_varlink *link, sd_json_variant *parameters, sd_varlink_method_flags_t flags, void *userdata) { @@ -170,7 +172,7 @@ static int vl_method_create_session(sd_varlink *link, sd_json_variant *parameter { "Remote", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_tristate, offsetof(CreateSessionParameters, remote), 0 }, { "RemoteUser", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(CreateSessionParameters, remote_user), 0 }, { "RemoteHost", SD_JSON_VARIANT_STRING, sd_json_dispatch_const_string, offsetof(CreateSessionParameters, remote_host), 0 }, - { "ExtraDeviceAccess", SD_JSON_VARIANT_BOOLEAN, sd_json_dispatch_stdbool, offsetof(CreateSessionParameters, extra_device_access), 0 }, + { "ExtraDeviceAccess", SD_JSON_VARIANT_ARRAY, sd_json_dispatch_strv, offsetof(CreateSessionParameters, extra_device_access), 0 }, {} }; @@ -180,7 +182,6 @@ static int vl_method_create_session(sd_varlink *link, sd_json_variant *parameter .class = _SESSION_CLASS_INVALID, .type = _SESSION_TYPE_INVALID, .remote = -1, - .extra_device_access = false, }; r = sd_varlink_dispatch(link, parameters, dispatch_table, &p); diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c index 00b93a3dc4f..cf8fe30ebea 100644 --- a/src/login/pam_systemd.c +++ b/src/login/pam_systemd.c @@ -814,7 +814,7 @@ typedef struct SessionContext { uint32_t vtnr; const char *tty; const char *display; - bool extra_device_access; + char **extra_device_access; bool remote; const char *remote_user; const char *remote_host; @@ -827,6 +827,10 @@ typedef struct SessionContext { bool incomplete; } SessionContext; +static void session_context_done(SessionContext *c) { + strv_free(c->extra_device_access); +} + static int create_session_message( sd_bus *bus, pam_handle_t *pamh, @@ -1150,7 +1154,7 @@ static int register_session( SD_JSON_BUILD_PAIR_BOOLEAN("Remote", c->remote), JSON_BUILD_PAIR_STRING_NON_EMPTY("RemoteUser", c->remote_user), JSON_BUILD_PAIR_STRING_NON_EMPTY("RemoteHost", c->remote_host), - JSON_BUILD_PAIR_CONDITION_BOOLEAN(c->extra_device_access, "ExtraDeviceAccess", c->extra_device_access)); + JSON_BUILD_PAIR_CONDITION_STRV(!strv_isempty(c->extra_device_access), "ExtraDeviceAccess", c->extra_device_access)); if (r < 0) return pam_syslog_errno(pamh, LOG_ERR, r, "Failed to issue io.systemd.Login.CreateSession varlink call: %m"); @@ -1317,7 +1321,11 @@ static int register_session( if (r != PAM_SUCCESS) return r; - r = update_environment(pamh, "XDG_SESSION_EXTRA_DEVICE_ACCESS", one_zero(c->extra_device_access)); + _cleanup_free_ char *extra_devices = strv_join(c->extra_device_access, ":"); + if (!extra_devices) + return pam_log_oom(pamh); + + r = update_environment(pamh, "XDG_SESSION_EXTRA_DEVICE_ACCESS", extra_devices); if (r != PAM_SUCCESS) return r; @@ -1769,7 +1777,7 @@ _public_ PAM_EXTERN int pam_sm_open_session( if (r != PAM_SUCCESS) return r; - SessionContext c = {}; + _cleanup_(session_context_done) SessionContext c = {}; r = pam_get_item_many( pamh, PAM_SERVICE, &c.service, @@ -1787,7 +1795,13 @@ _public_ PAM_EXTERN int pam_sm_open_session( c.desktop = getenv_harder(pamh, "XDG_SESSION_DESKTOP", desktop_pam); c.area = getenv_harder(pamh, "XDG_AREA", area_pam); c.incomplete = getenv_harder_bool(pamh, "XDG_SESSION_INCOMPLETE", false); - c.extra_device_access = getenv_harder_bool(pamh, "XDG_SESSION_EXTRA_DEVICE_ACCESS", false); + + const char *extra_device_access = getenv_harder(pamh, "XDG_SESSION_EXTRA_DEVICE_ACCESS", NULL); + if (extra_device_access) { + c.extra_device_access = strv_split(extra_device_access, ":"); + if (!c.extra_device_access) + return pam_log_oom(pamh); + } r = pam_get_data_many( pamh, diff --git a/src/shared/varlink-io.systemd.Login.c b/src/shared/varlink-io.systemd.Login.c index fe49a9221fd..cf09d182866 100644 --- a/src/shared/varlink-io.systemd.Login.c +++ b/src/shared/varlink-io.systemd.Login.c @@ -65,10 +65,9 @@ static SD_VARLINK_DEFINE_METHOD( SD_VARLINK_DEFINE_INPUT(RemoteUser, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), SD_VARLINK_FIELD_COMMENT("Host name of the remote host"), SD_VARLINK_DEFINE_INPUT(RemoteHost, SD_VARLINK_STRING, SD_VARLINK_NULLABLE), - SD_VARLINK_FIELD_COMMENT("If true this session is granted access to additional hardware devices, " - "typically useful for remote, graphical sessions. " - "This adds access for all devices tagged with \"xaccess\" in udev."), - SD_VARLINK_DEFINE_INPUT(ExtraDeviceAccess, SD_VARLINK_BOOL, SD_VARLINK_NULLABLE), + SD_VARLINK_FIELD_COMMENT("List of additional hardware devices that this session is granted access to." + "For every $ID in the list, this adds access for all devices tagged with \"xaccess-$ID\" in udev."), + SD_VARLINK_DEFINE_INPUT(ExtraDeviceAccess, SD_VARLINK_STRING, SD_VARLINK_NULLABLE|SD_VARLINK_ARRAY), SD_VARLINK_FIELD_COMMENT("The identifier string of the session of the user."), SD_VARLINK_DEFINE_OUTPUT(Id, SD_VARLINK_STRING, 0), SD_VARLINK_FIELD_COMMENT("The runtime path ($XDG_RUNTIME_DIR) of the user."), diff --git a/src/systemd/sd-login.h b/src/systemd/sd-login.h index 042d7539135..f9cfaf6a2fe 100644 --- a/src/systemd/sd-login.h +++ b/src/systemd/sd-login.h @@ -150,8 +150,10 @@ int sd_session_is_active(const char *session); /* Return 1 if the session is remote. */ int sd_session_is_remote(const char *session); -/* Return 1 if the session is granted extra device access. */ -int sd_session_has_extra_device_access(const char *session); +/* Return extra hardware devices that the session is granted access to. + * For every $ID in the list, this adds access for all devices tagged with + * "xaccess-$ID" in udev. */ +int sd_session_get_extra_device_access(const char *session, char ***ret_ids); /* Get state from session. Possible states: online, active, closing. * This function is a more generic version of sd_session_is_active(). */ diff --git a/src/udev/udev-builtin-uaccess.c b/src/udev/udev-builtin-uaccess.c index e77fc709094..9fd006e570c 100644 --- a/src/udev/udev-builtin-uaccess.c +++ b/src/udev/udev-builtin-uaccess.c @@ -63,34 +63,58 @@ static int builtin_uaccess(UdevEvent *event, int argc, char *argv[]) { } } - r = sd_device_has_tag(dev, "xaccess"); - if (r < 0) - return log_device_error_errno(dev, r, "Failed to query device xaccess tag: %m"); + bool has_xaccess = false; + FOREACH_DEVICE_CURRENT_TAG(dev, tag) + if (startswith(tag, "xaccess-")) { + has_xaccess = true; + break; + } - if (r > 0) { + if (has_xaccess) { r = sd_get_sessions(&sessions); if (r < 0) return log_device_error_errno(dev, r, "Failed to list sessions: %m"); STRV_FOREACH(s, sessions) { _cleanup_free_ char *state = NULL; - if (sd_session_get_state(*s, &state) < 0) { + r = sd_session_get_state(*s, &state); + if (r < 0) { log_device_debug_errno(dev, r, "Failed to query state for session %s, ignoring: %m", *s); continue; } if (streq(state, "closing")) continue; - r = sd_session_has_extra_device_access(*s); + + r = sd_session_get_uid(*s, &uid); if (r < 0) { - log_device_debug_errno(dev, r, "Failed to query extra device access for session %s, ignoring: %m", *s); + log_device_debug_errno(dev, r, "Failed to query uid for session %s, ignoring: %m", *s); continue; } - if (r == 0) - continue; - if (sd_session_get_uid(*s, &uid) < 0) { - log_device_debug_errno(dev, r, "Failed to query uid for session %s, ignoring: %m", *s); + + _cleanup_strv_free_ char **extra_devices = NULL; + r = sd_session_get_extra_device_access(*s, &extra_devices); + if (r < 0) { + log_device_debug_errno(dev, r, "Failed to query extra device access for session %s, ignoring: %m", *s); continue; } + + bool match = false; + STRV_FOREACH(id, extra_devices) { + _cleanup_free_ char *tag = strjoin("xaccess-", *id); + if (!tag) + return log_oom(); + + r = sd_device_has_current_tag(dev, tag); + if (r < 0) + return log_device_error_errno(dev, r, "Failed to query %s tag: %m", tag); + if (r > 0) { + match = true; + break; + } + } + if (!match) + continue; + if (set_ensure_put(&uids, NULL, UID_TO_PTR(uid)) < 0) return log_oom(); }