]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
login: Add XDG_SESSION_EXTRA_DEVICE_ACCESS variable for additional access
authorAlessandro Astone <alessandro.astone@canonical.com>
Wed, 26 Nov 2025 16:23:13 +0000 (17:23 +0100)
committerAlessandro Astone <alessandro.astone@canonical.com>
Fri, 6 Feb 2026 15:20:18 +0000 (16:20 +0100)
A session created with XDG_SESSION_EXTRA_DEVICE_ACCESS will be granted
additional powers.
Exactly which powers are granted is going to be defined by udevd.

12 files changed:
src/core/manager.c
src/libsystemd/libsystemd.sym
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

index 277935bab2074c2fee65ac12937700cfac72547a..fec110656527357e0f4f1ba8e602451eb9b5cd08 100644 (file)
@@ -697,6 +697,7 @@ int manager_default_environment(Manager *m) {
                                     "XDG_SESSION_CLASS",
                                     "XDG_SESSION_TYPE",
                                     "XDG_SESSION_DESKTOP",
+                                    "XDG_SESSION_EXTRA_DEVICE_ACCESS",
                                     "XDG_SEAT",
                                     "XDG_VTNR");
         }
index a1fa7942642c7ea04366d7fa113314b57625be76..735aa78214284d69e811fdc84566705a7f847f2a 100644 (file)
@@ -1085,3 +1085,8 @@ global:
         sd_event_get_exit_on_idle;
         sd_varlink_is_connected;
 } LIBSYSTEMD_258;
+
+LIBSYSTEMD_260 {
+global:
+        sd_session_has_extra_device_access;
+} LIBSYSTEMD_259;
index f65fb2077e1079f0219568303550842843ef78e4..bf214ab661b0e98823ef975a008ae9d5d6e3c8ca 100644 (file)
@@ -677,6 +677,25 @@ _public_ int sd_session_is_remote(const char *session) {
         return parse_boolean(s);
 }
 
+_public_ int sd_session_has_extra_device_access(const char *session) {
+        _cleanup_free_ char *p = NULL, *s = NULL;
+        int r;
+
+        r = file_of_session(session, &p);
+        if (r < 0)
+                return r;
+
+        r = parse_env_file(/* f= */ NULL, p, "EXTRA_DEVICE_ACCESS", &s);
+        if (r == -ENOENT)
+                return -ENXIO;
+        if (r < 0)
+                return r;
+        if (isempty(s))
+                return -ENODATA;
+
+        return parse_boolean(s);
+}
+
 _public_ int sd_session_get_state(const char *session, char **ret_state) {
         _cleanup_free_ char *p = NULL, *s = NULL;
         int r;
index ab113afbab0f894a74ca0330e3a89a0a910ee11d..8ccaa9a1cd4d2953bb8a4d4839cd4208252f53c9 100644 (file)
@@ -898,6 +898,7 @@ int manager_create_session(
                 bool remote,
                 const char *remote_user,
                 const char *remote_host,
+                bool extra_device_access,
                 Session **ret_session) {
 
         bool mangle_class = false;
@@ -1004,6 +1005,7 @@ 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;
 
@@ -1227,6 +1229,7 @@ static int manager_create_session_by_bus(
                         remote,
                         remote_user,
                         remote_host,
+                        /* extra_device_access= */ false,
                         &session);
         if (r == -EBUSY)
                 return sd_bus_error_set(error, BUS_ERROR_SESSION_BUSY, "Already running in a session or user slice");
index febc78aa4b52d99beea22eab51347abf7aab6721..e254e62195ee8191e0617285bf6fdf95fa3d4d02 100644 (file)
@@ -57,6 +57,7 @@ int manager_create_session(
                 bool remote,
                 const char *remote_user,
                 const char *remote_host,
+                bool extra_device_access,
                 Session **ret_session);
 
 extern const BusObjectImplementation manager_object;
index e6513949b198587c6496005d7f1980c7c6581d97..21d16dbd8d865f59b8bf0055a97f51bd0596eb89 100644 (file)
@@ -985,6 +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("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 b30252cd09c68241f4cc26937d10f244599af1ee..3724de793dccaf92b905d44ea5d5969d7bce818b 100644 (file)
@@ -307,12 +307,14 @@ 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);
@@ -453,6 +455,7 @@ static int session_load_leader(Session *s, uint64_t pidfdid) {
 
 int session_load(Session *s) {
         _cleanup_free_ char *remote = NULL,
+                *extra_device_access = NULL,
                 *seat = NULL,
                 *tty_validity = NULL,
                 *vtnr = NULL,
@@ -478,34 +481,35 @@ int session_load(Session *s) {
         assert(s);
 
         r = parse_env_file(NULL, s->state_file,
-                           "REMOTE",          &remote,
-                           "SCOPE",           &s->scope,
-                           "SCOPE_JOB",       &s->scope_job,
-                           "FIFO",            &fifo_path,
-                           "SEAT",            &seat,
-                           "TTY",             &s->tty,
-                           "TTY_VALIDITY",    &tty_validity,
-                           "DISPLAY",         &s->display,
-                           "REMOTE_HOST",     &s->remote_host,
-                           "REMOTE_USER",     &s->remote_user,
-                           "SERVICE",         &s->service,
-                           "DESKTOP",         &s->desktop,
-                           "VTNR",            &vtnr,
-                           "STATE",           &state,
-                           "POSITION",        &position,
-                           "LEADER",          &leader_pid,
-                           "LEADER_FD_SAVED", &leader_fd_saved,
-                           "LEADER_PIDFDID",  &leader_pidfdid,
-                           "TYPE",            &type,
-                           "ORIGINAL_TYPE",   &original_type,
-                           "CLASS",           &class,
-                           "UID",             &uid,
-                           "REALTIME",        &realtime,
-                           "MONOTONIC",       &monotonic,
-                           "CONTROLLER",      &controller,
-                           "ACTIVE",          &active,
-                           "DEVICES",         &devices,
-                           "IS_DISPLAY",      &is_display);
+                           "REMOTE",              &remote,
+                           "EXTRA_DEVICE_ACCESS", &extra_device_access,
+                           "SCOPE",               &s->scope,
+                           "SCOPE_JOB",           &s->scope_job,
+                           "FIFO",                &fifo_path,
+                           "SEAT",                &seat,
+                           "TTY",                 &s->tty,
+                           "TTY_VALIDITY",        &tty_validity,
+                           "DISPLAY",             &s->display,
+                           "REMOTE_HOST",         &s->remote_host,
+                           "REMOTE_USER",         &s->remote_user,
+                           "SERVICE",             &s->service,
+                           "DESKTOP",             &s->desktop,
+                           "VTNR",                &vtnr,
+                           "STATE",               &state,
+                           "POSITION",            &position,
+                           "LEADER",              &leader_pid,
+                           "LEADER_FD_SAVED",     &leader_fd_saved,
+                           "LEADER_PIDFDID",      &leader_pidfdid,
+                           "TYPE",                &type,
+                           "ORIGINAL_TYPE",       &original_type,
+                           "CLASS",               &class,
+                           "UID",                 &uid,
+                           "REALTIME",            &realtime,
+                           "MONOTONIC",           &monotonic,
+                           "CONTROLLER",          &controller,
+                           "ACTIVE",              &active,
+                           "DEVICES",             &devices,
+                           "IS_DISPLAY",          &is_display);
         if (r < 0)
                 return log_error_errno(r, "Failed to read %s: %m", s->state_file);
 
@@ -539,6 +543,12 @@ int session_load(Session *s) {
                         s->remote = k;
         }
 
+        if (extra_device_access) {
+                k = parse_boolean(extra_device_access);
+                if (k >= 0)
+                        s->extra_device_access = k;
+        }
+
         if (vtnr)
                 (void) safe_atou(vtnr, &s->vtnr);
 
index d339006f17e784559175cdcbd056018439b11e85..ddebd43e55d222094801bed7ecb5b2f434c266c2 100644 (file)
@@ -121,6 +121,7 @@ typedef struct Session {
         char *remote_host;
         char *service;
         char *desktop;
+        bool extra_device_access;
 
         char *scope;
         char *scope_job;
index a17f64271e8a4cc6ab040ed1987db3ff6f37d56c..0016f276f372768ce348635d2f94d3dd96803352 100644 (file)
@@ -145,6 +145,7 @@ typedef struct CreateSessionParameters {
         int remote;
         const char *remote_user;
         const char *remote_host;
+        bool extra_device_access;
 } CreateSessionParameters;
 
 static void create_session_parameters_done(CreateSessionParameters *p) {
@@ -156,19 +157,20 @@ static int vl_method_create_session(sd_varlink *link, sd_json_variant *parameter
         int r;
 
         static const sd_json_dispatch_field dispatch_table[] = {
-                { "UID",        _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uid_gid,      offsetof(CreateSessionParameters, uid),         SD_JSON_MANDATORY },
-                { "PID",        _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_pidref,          offsetof(CreateSessionParameters, pid),         SD_JSON_STRICT    },
-                { "Service",    SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string, offsetof(CreateSessionParameters, service),     0                 },
-                { "Type",       SD_JSON_VARIANT_STRING,        json_dispatch_session_type,    offsetof(CreateSessionParameters, type),        SD_JSON_MANDATORY },
-                { "Class",      SD_JSON_VARIANT_STRING,        json_dispatch_session_class,   offsetof(CreateSessionParameters, class),       SD_JSON_MANDATORY },
-                { "Desktop",    SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string, offsetof(CreateSessionParameters, desktop),     SD_JSON_STRICT    },
-                { "Seat",       SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string, offsetof(CreateSessionParameters, seat),        0                 },
-                { "VTNr",       _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint,         offsetof(CreateSessionParameters, vtnr),        0                 },
-                { "TTY",        SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string, offsetof(CreateSessionParameters, tty),         0                 },
-                { "Display",    SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string, offsetof(CreateSessionParameters, display),     0                 },
-                { "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                 },
+                { "UID",               _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uid_gid,      offsetof(CreateSessionParameters, uid),                 SD_JSON_MANDATORY },
+                { "PID",               _SD_JSON_VARIANT_TYPE_INVALID, json_dispatch_pidref,          offsetof(CreateSessionParameters, pid),                 SD_JSON_STRICT    },
+                { "Service",           SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string, offsetof(CreateSessionParameters, service),             0                 },
+                { "Type",              SD_JSON_VARIANT_STRING,        json_dispatch_session_type,    offsetof(CreateSessionParameters, type),                SD_JSON_MANDATORY },
+                { "Class",             SD_JSON_VARIANT_STRING,        json_dispatch_session_class,   offsetof(CreateSessionParameters, class),               SD_JSON_MANDATORY },
+                { "Desktop",           SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string, offsetof(CreateSessionParameters, desktop),             SD_JSON_STRICT    },
+                { "Seat",              SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string, offsetof(CreateSessionParameters, seat),                0                 },
+                { "VTNr",              _SD_JSON_VARIANT_TYPE_INVALID, sd_json_dispatch_uint,         offsetof(CreateSessionParameters, vtnr),                0                 },
+                { "TTY",               SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string, offsetof(CreateSessionParameters, tty),                 0                 },
+                { "Display",           SD_JSON_VARIANT_STRING,        sd_json_dispatch_const_string, offsetof(CreateSessionParameters, display),             0                 },
+                { "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                 },
                 {}
         };
 
@@ -178,6 +180,7 @@ 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);
@@ -264,6 +267,7 @@ static int vl_method_create_session(sd_varlink *link, sd_json_variant *parameter
                         p.remote,
                         p.remote_user,
                         p.remote_host,
+                        p.extra_device_access,
                         &session);
         if (r == -EBUSY)
                 return sd_varlink_error(link, "io.systemd.Login.AlreadySessionMember", /* parameters= */ NULL);
index ea4cf8193b1e1080f3f67e36c205b4e044ca64a9..00b93a3dc4f243fdbcdf3bd9b387511e48127985 100644 (file)
@@ -814,6 +814,7 @@ typedef struct SessionContext {
         uint32_t vtnr;
         const char *tty;
         const char *display;
+        bool extra_device_access;
         bool remote;
         const char *remote_user;
         const char *remote_host;
@@ -1148,7 +1149,8 @@ static int register_session(
                                         JSON_BUILD_PAIR_STRING_NON_EMPTY("Display", c->display),
                                         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_STRING_NON_EMPTY("RemoteHost", c->remote_host),
+                                        JSON_BUILD_PAIR_CONDITION_BOOLEAN(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");
@@ -1315,6 +1317,10 @@ 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));
+        if (r != PAM_SUCCESS)
+                return r;
+
         r = update_environment(pamh, "XDG_SEAT", real_seat);
         if (r != PAM_SUCCESS)
                 return r;
@@ -1781,6 +1787,7 @@ _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);
 
         r = pam_get_data_many(
                         pamh,
index 92cb2dfd75cf8289fe946c0b721c5cc863027675..fe49a9221fd0912ff7332a29d220de55383c3751 100644 (file)
@@ -65,6 +65,10 @@ 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("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 70f05cf306f1673b0c3e66e590291714139d3a08..042d753913598ed876212759053e6ff5f58fdad0 100644 (file)
@@ -150,6 +150,9 @@ 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);
+
 /* Get state from session. Possible states: online, active, closing.
  * This function is a more generic version of sd_session_is_active(). */
 int sd_session_get_state(const char *session, char **ret_state);