]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
xaccess: Rework from boolean into a list of tags
authorAlessandro Astone <alessandro.astone@canonical.com>
Wed, 11 Feb 2026 14:02:53 +0000 (15:02 +0100)
committerAlessandro Astone <alessandro.astone@canonical.com>
Tue, 17 Feb 2026 14:27:24 +0000 (15:27 +0100)
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
18 files changed:
man/org.freedesktop.login1.xml
man/pam_systemd.xml
man/rules/meson.build
man/sd-login.xml
man/sd_session_is_active.xml
src/libsystemd/libsystemd.sym
src/libsystemd/sd-json/json-util.h
src/libsystemd/sd-login/sd-login.c
src/login/logind-dbus.c
src/login/logind-dbus.h
src/login/logind-session-dbus.c
src/login/logind-session.c
src/login/logind-session.h
src/login/logind-varlink.c
src/login/pam_systemd.c
src/shared/varlink-io.systemd.Login.c
src/systemd/sd-login.h
src/udev/udev-builtin-uaccess.c

index cc4a146fff55caada0086ee34b1d438bc32d30ed..464fdab108d8b7278a2bf9b2ac71cf286d1d5ea7 100644 (file)
@@ -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 {
       <para><varname>RemoteHost</varname> and <varname>RemoteUser</varname> encode the remote host and user
       if this is a remote session, or an empty string otherwise.</para>
 
-      <para><varname>ExtraDeviceAccess</varname> 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 <literal>xaccess</literal> in udev.</para>
+      <para><varname>ExtraDeviceAccess</varname> encodes the set of additional hardware devices that the session
+      is granted access to. For every <literal><replaceable>ID</replaceable></literal> in the list, the session
+      is granted access to all devices tagged with <literal>xaccess-<replaceable>ID</replaceable></literal> in udev.</para>
 
       <para><varname>Service</varname> encodes the PAM service name that registered the session.</para>
 
index ee3060d670e280a345c4fc9627c786406511915d..5482ced0677456e7f91f81eb03227e8652bc4b9a 100644 (file)
       <varlistentry>
         <term><varname>$XDG_SESSION_EXTRA_DEVICE_ACCESS</varname></term>
 
-        <listitem><para>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 <literal>xaccess</literal> in udev. Typically, rendering device nodes of
-        the GPU are tagged like this.</para>
+        <listitem><para>The set of additional hardware devices that the session shall be granted access to.
+        For every <literal><replaceable>ID</replaceable></literal> in the list, the session is granted
+        access to all devices tagged with <literal>xaccess-<replaceable>ID</replaceable></literal> in udev.</para>
 
         <xi:include href="version-info.xml" xpointer="v260"/></listitem>
       </varlistentry>
index 606cb72d2940dc4df752fbf98e9e26f0519909e7..9eae3e8249f3c87c1bc1218c3a08521e8ee284c1 100644 (file)
@@ -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',
index 47ea4680b63730179c05fa318f071f9125b42b55..6c8745d358adb42f2086bc74eb787a4f5a42b401 100644 (file)
       </varlistentry>
 
       <varlistentry>
-        <term>Tag <literal>xaccess</literal></term>
+        <term>Tag <literal>xaccess-*</literal></term>
 
-        <listitem><para>When set, access to this device is granted to sessions
-        created with <literal>ExtraDeviceAccess</literal>. This is typically useful
-        for graphical, remote sessions. As the <literal>ExtraDeviceAccess</literal>
-        sessions open and close, access to the device is updated accordingly.</para>
+        <listitem><para>When <literal>xaccess-<replaceable>ID</replaceable></literal>
+        is set, access to this device is granted to sessions created with
+        <literal><replaceable>ID</replaceable></literal> listed in <literal>ExtraDeviceAccess</literal>.
+        As the sessions with some <literal>ExtraDeviceAccess</literal> open and close,
+        access to the device is updated accordingly.</para>
 
         <xi:include href="version-info.xml" xpointer="v260"/></listitem>
       </varlistentry>
index 3a3935cfef821e7a304b3311d981d85308ba86b1..f1c26611850a82f857b331efab55fc306ff9fc5a 100644 (file)
@@ -34,7 +34,7 @@
     <refname>sd_session_get_remote_host</refname>
     <refname>sd_session_get_remote_user</refname>
     <refname>sd_session_get_leader</refname>
-    <refname>sd_session_has_extra_device_access</refname>
+    <refname>sd_session_get_extra_device_access</refname>
     <refpurpose>Determine state of a specific session</refpurpose>
   </refnamediv>
 
       </funcprototype>
 
       <funcprototype>
-        <funcdef>int <function>sd_session_has_extra_device_access</function></funcdef>
+        <funcdef>int <function>sd_session_get_extra_device_access</function></funcdef>
         <paramdef>const char *<parameter>session</parameter></paramdef>
+        <paramdef>char ***<parameter>ret_ids</parameter></paramdef>
       </funcprototype>
     </funcsynopsis>
   </refsynopsisdiv>
     session identifier. This function will return an error if the seat
     does not support VTs.</para>
 
-    <para><function>sd_session_has_extra_device_access()</function> 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 <literal>xaccess</literal> in udev.</para>
+    <para><function>sd_session_get_extra_device_access()</function> may
+    be used to determine which additional hardware devices the session
+    is granted access to. For every <literal><replaceable>ID</replaceable></literal>
+    in the list, the session is granted access to all devices tagged with
+    <literal>xaccess-<replaceable>ID</replaceable></literal> in udev.</para>
 
     <para>If the <varname>session</varname> parameter of any of these
     functions is passed as <constant>NULL</constant>, the operation is
     <title>Return Value</title>
 
     <para>If the test succeeds,
-    <function>sd_session_is_active()</function>,
-    <function>sd_session_is_remote()</function>, and
-    <function>sd_session_has_extra_device_access()</function>
+    <function>sd_session_is_active()</function> and
+    <function>sd_session_is_remote()</function>
     return a positive integer; if it fails, 0.  On success,
     <function>sd_session_get_state()</function>,
     <function>sd_session_get_uid()</function>,
     <function>sd_session_get_display()</function>,
     <function>sd_session_get_leader()</function>,
     <function>sd_session_get_remote_user()</function>,
-    <function>sd_session_get_remote_host()</function> and
-    <function>sd_session_get_tty()</function> return 0 or
-    a positive integer. On failure, these calls return a
+    <function>sd_session_get_remote_host()</function>,
+    <function>sd_session_get_tty()</function>, and
+    <function>sd_session_get_extra_device_access()</function>
+    return 0 or a positive integer. On failure, these calls return a
     negative errno-style error code.</para>
 
     <refsect2>
     <para><function>sd_session_get_username()</function>,
     <function>sd_session_get_start_time()</function>, and
     <function>sd_session_get_leader()</function> were added in version 254.</para>
-    <para><function>sd_session_has_extra_device_access()</function> was added in version 260.</para>
+    <para><function>sd_session_get_extra_device_access()</function> was added in version 260.</para>
   </refsect1>
 
   <refsect1>
index 735aa78214284d69e811fdc84566705a7f847f2a..aa270a483a40e8e4097084e31177ef3ab7c6e181 100644 (file)
@@ -1088,5 +1088,5 @@ global:
 
 LIBSYSTEMD_260 {
 global:
-        sd_session_has_extra_device_access;
+        sd_session_get_extra_device_access;
 } LIBSYSTEMD_259;
index 5365eedcae5420e52505f8e3c5fab2eb25556d70..d06a72aef9af38baa726760f8ce487ccdf71aea5 100644 (file)
@@ -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);
index bf214ab661b0e98823ef975a008ae9d5d6e3c8ca..1331190c2e3b91cd459fd9f1223f8692d9c30414 100644 (file)
@@ -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) {
index 8ccaa9a1cd4d2953bb8a4d4839cd4208252f53c9..87cc4f14bc8683fca36044ca10b07bd4e8360311 100644 (file)
@@ -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");
index e254e62195ee8191e0617285bf6fdf95fa3d4d02..1ece1c68c8cc91aa9427e49134c4c3847e8da463 100644 (file)
@@ -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;
index 21d16dbd8d865f59b8bf0055a97f51bd0596eb89..4da9bb242557909a9eb0d691558b6eadfb074a84 100644 (file)
@@ -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),
index 2b2c36b1d4654711dc78f44ce0283d1dc67b6f8d..72cad136650c212dee5960488775d50544d04cfb 100644 (file)
@@ -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;
 }
index ddebd43e55d222094801bed7ecb5b2f434c266c2..f51eed24fa0f16f95c235116275ecf47fb20848b 100644 (file)
@@ -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;
index 0016f276f372768ce348635d2f94d3dd96803352..a1fdac01c907b96ddcca62a8955467cf53a57ee1 100644 (file)
@@ -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);
index 00b93a3dc4f243fdbcdf3bd9b387511e48127985..cf8fe30ebeac15f398d045dff3b4c940b656732f 100644 (file)
@@ -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,
index fe49a9221fd0912ff7332a29d220de55383c3751..cf09d18286679684720c16c9e45edfdaffe30f4c 100644 (file)
@@ -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."),
index 042d753913598ed876212759053e6ff5f58fdad0..f9cfaf6a2fe162e3f38ab406348a8d733bfe94e1 100644 (file)
@@ -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(). */
index e77fc709094a17af08380cd44c0f1bdcabb14517..9fd006e570c5b387a4ea2139083c06ec4836cfe4 100644 (file)
@@ -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();
                 }