mirror of
https://github.com/systemd/systemd.git
synced 2025-03-19 22:50:17 +03:00
logind: introduce "user-light" session class
This new session class is to "user" what "background" is to "background-light": it doesn't cause the per-user service manager to start. This new session class is now the default if no session class was provided at session registration time and the following conditions hold: 1. The session is not graphical 2. The user is not a regular user (but not root) Or in other words root and system users won't get a service manager started automatically if they go through a PAM session as part of things like cron or ftp. They will however still get one if they log in graphically. This changes behaviour a bit, but hopefully in OK was. This also makes "background-light" for system users incl. root. This addresses one of the ideas discussed in #34988.
This commit is contained in:
parent
a6ad410ffa
commit
cf8f6cd057
17
NEWS
17
NEWS
@ -16,6 +16,23 @@ CHANGES WITH 258 in spe:
|
||||
enabled by default. This brings cmdline expansion of transient
|
||||
scopes on par with services.
|
||||
|
||||
* systemd-logind PAM sessions that previously were automatically
|
||||
determined to be of class "background", and which are owned by root
|
||||
or system accounts, will now automatically be set to class
|
||||
"background-light" instead. PAM sessions that previously were
|
||||
automatically determined to be of class "user", and which are owned
|
||||
by non-root system users, will now automatically be set to class
|
||||
"user-light" instead. This effectively means that cron jobs or FTP
|
||||
sessions (i.e. all PAM sessions that have no TTY assigned and neither
|
||||
are graphical) for system users no longer pull in a service manager
|
||||
by default. This behaviour can be changed by explicitly setting the
|
||||
session class (for example via the class= parameter to
|
||||
pam_systemd.so, or by setting the XDG_SESSION_CLASS environment
|
||||
variable as input for the service's PAM stack). This change does not
|
||||
affect graphical sessions, nor does it affect regular users. This is
|
||||
an incompatible change of sorts, since per-user services will
|
||||
typically not be available for such PAM sessions of system users.
|
||||
|
||||
Announcements of Future Feature Removals:
|
||||
|
||||
* The D-Bus method org.freedesktop.systemd1.StartAuxiliaryScope() is
|
||||
|
6
TODO
6
TODO
@ -134,12 +134,6 @@ Features:
|
||||
really be recognizable via a message id and come with an explanatory catalog
|
||||
message
|
||||
|
||||
* logind: introduce "user-light" session class, that is to "user" what
|
||||
"background-light" is to "background". Then, in logind, if no user class is
|
||||
specified, and we are not logging in graphically default to this session
|
||||
class for non-regular users. Effect: if you log into a system user for some
|
||||
reason, yu won't get the service manager by default.
|
||||
|
||||
* introduce new ANSI sequence for communicating log level and structured error
|
||||
metadata to terminals.
|
||||
|
||||
|
@ -115,6 +115,14 @@
|
||||
<entry><constant>user-early</constant></entry>
|
||||
<entry>Similar to <literal>user</literal> but sessions of this class are not ordered after <citerefentry><refentrytitle>systemd-user-sessions.service</refentrytitle><manvolnum>8</manvolnum></citerefentry>, i.e. may be started before regular sessions are allowed to be established. This session class is the default for sessions of the root user that would otherwise qualify for the <constant>user</constant> class, see above. (Added in v256.)</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><constant>user-light</constant></entry>
|
||||
<entry>Similar to <constant>user</constant>, but sessions of this class will not pull in the <citerefentry><refentrytitle>user@.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> of the user, and thus possibly have no service manager of the user running. (Added in v258.)</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><constant>user-early-light</constant></entry>
|
||||
<entry>Similar to <constant>user-early</constant>, but sessions of this class will not pull in the <citerefentry><refentrytitle>user@.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> of the user, and thus possibly have no service manager of the user running. (Added in v258.)</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><constant>user-incomplete</constant></entry>
|
||||
<entry>Similar to <literal>user</literal> but for sessions which are not fully set up yet, i.e. have no home directory mounted or similar. This is used by <citerefentry><refentrytitle>systemd-homed.service</refentrytitle><manvolnum>8</manvolnum></citerefentry> to allow users to log in via <citerefentry project='man-pages'><refentrytitle>ssh</refentrytitle><manvolnum>1</manvolnum></citerefentry> before their home directory is mounted, delaying the mount until the user provided the unlock password. Sessions of this class are upgraded to the regular <constant>user</constant> class once the home directory is activated.</entry>
|
||||
@ -133,7 +141,7 @@
|
||||
</row>
|
||||
<row>
|
||||
<entry><constant>background-light</constant></entry>
|
||||
<entry>Similar to <constant>background</constant>, but sessions of this class will not pull in the <citerefentry><refentrytitle>user@.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> of the user, and thus possibly have no services of the user running. (Added in v256.)</entry>
|
||||
<entry>Similar to <constant>background</constant>, but sessions of this class will not pull in the <citerefentry><refentrytitle>user@.service</refentrytitle><manvolnum>5</manvolnum></citerefentry> of the user, and thus possibly have no service manager of the user running. (Added in v256.)</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry><constant>manager</constant></entry>
|
||||
|
@ -216,10 +216,10 @@
|
||||
|
||||
<para><function>sd_session_get_class()</function> may be used to determine the class of the session
|
||||
identified by the specified session identifier. The returned string is one of <literal>user</literal>,
|
||||
<literal>user-early</literal>, <literal>user-incomplete</literal>, <literal>greeter</literal>,
|
||||
<literal>lock-screen</literal>, <literal>background</literal>, <literal>background-light</literal>,
|
||||
<literal>manager</literal> or <literal>manager-early</literal> and needs to be freed with the libc
|
||||
<citerefentry
|
||||
<literal>user-early</literal>, <literal>user-light</literal>, <literal>user-early-light</literal>,
|
||||
<literal>user-incomplete</literal>, <literal>greeter</literal>, <literal>lock-screen</literal>,
|
||||
<literal>background</literal>, <literal>background-light</literal>, <literal>manager</literal> or
|
||||
<literal>manager-early</literal> and needs to be freed with the libc <citerefentry
|
||||
project='man-pages'><refentrytitle>free</refentrytitle><manvolnum>3</manvolnum></citerefentry> call after
|
||||
use.</para>
|
||||
|
||||
|
@ -893,6 +893,7 @@ int manager_create_session(
|
||||
const char *remote_host,
|
||||
Session **ret_session) {
|
||||
|
||||
bool mangle_class = false;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
@ -920,6 +921,10 @@ int manager_create_session(
|
||||
class = SESSION_BACKGROUND;
|
||||
else
|
||||
class = SESSION_USER;
|
||||
|
||||
/* If we determined the class automatically, then let's later potentially change it to early
|
||||
* or light flavours, once we learn the disposition of the user */
|
||||
mangle_class = true;
|
||||
}
|
||||
|
||||
/* Check if we are already in a logind session, and if so refuse. */
|
||||
@ -962,6 +967,25 @@ int manager_create_session(
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
||||
/* If we picked the session class on our own, and the user is not a regular one, and the session is
|
||||
* not a graphical one then do not pull in session manager by default. For root make a special
|
||||
* exception: for TTY logins leave the service manager on, but relax the /run/nologin
|
||||
* restrictions. */
|
||||
if (mangle_class &&
|
||||
IN_SET(user_record_disposition(user->user_record), USER_INTRINSIC, USER_SYSTEM, USER_DYNAMIC)) {
|
||||
|
||||
if (class == SESSION_USER) {
|
||||
if (user_record_is_root(user->user_record))
|
||||
class = SESSION_USER_EARLY;
|
||||
else if (SESSION_TYPE_IS_GRAPHICAL(type))
|
||||
class = SESSION_USER;
|
||||
else
|
||||
class = SESSION_USER_LIGHT;
|
||||
|
||||
} else if (class == SESSION_BACKGROUND)
|
||||
class = SESSION_BACKGROUND_LIGHT;
|
||||
}
|
||||
|
||||
r = manager_add_session(m, id, &session);
|
||||
if (r < 0)
|
||||
goto fail;
|
||||
|
@ -1704,6 +1704,8 @@ static const char* const session_class_table[_SESSION_CLASS_MAX] = {
|
||||
[SESSION_USER] = "user",
|
||||
[SESSION_USER_EARLY] = "user-early",
|
||||
[SESSION_USER_INCOMPLETE] = "user-incomplete",
|
||||
[SESSION_USER_LIGHT] = "user-light",
|
||||
[SESSION_USER_EARLY_LIGHT] = "user-early-light",
|
||||
[SESSION_GREETER] = "greeter",
|
||||
[SESSION_LOCK_SCREEN] = "lock-screen",
|
||||
[SESSION_BACKGROUND] = "background",
|
||||
|
@ -23,6 +23,8 @@ typedef enum SessionClass {
|
||||
SESSION_USER, /* A regular user session */
|
||||
SESSION_USER_EARLY, /* A user session, that is not ordered after systemd-user-sessions.service (i.e. for root) */
|
||||
SESSION_USER_INCOMPLETE, /* A user session that is only half-way set up and doesn't pull in the service manager, and can be upgraded to a full user session later */
|
||||
SESSION_USER_LIGHT, /* Just like SESSION_USER, but doesn't pull in service manager */
|
||||
SESSION_USER_EARLY_LIGHT, /* Just like SESSION_USER_EARLY, but doesn't pull in service manager */
|
||||
SESSION_GREETER, /* A login greeter pseudo-session */
|
||||
SESSION_LOCK_SCREEN, /* A lock screen */
|
||||
SESSION_BACKGROUND, /* Things like cron jobs, which are non-interactive */
|
||||
@ -36,10 +38,12 @@ typedef enum SessionClass {
|
||||
|
||||
/* Whether we shall allow sessions of this class to run before 'systemd-user-sessions.service'. It's
|
||||
* generally set for root sessions, but no one else. */
|
||||
#define SESSION_CLASS_IS_EARLY(class) IN_SET((class), SESSION_USER_EARLY, SESSION_MANAGER_EARLY)
|
||||
#define SESSION_CLASS_IS_EARLY(class) IN_SET((class), SESSION_USER_EARLY, SESSION_USER_EARLY_LIGHT, SESSION_MANAGER_EARLY)
|
||||
|
||||
/* Which session classes want their own scope units? (all of them, except the manager, which comes in its own service unit already */
|
||||
#define SESSION_CLASS_WANTS_SCOPE(class) IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_USER_INCOMPLETE, SESSION_GREETER, SESSION_LOCK_SCREEN, SESSION_BACKGROUND, SESSION_BACKGROUND_LIGHT)
|
||||
#define SESSION_CLASS_WANTS_SCOPE(class) IN_SET((class), \
|
||||
SESSION_USER, SESSION_USER_EARLY, SESSION_USER_INCOMPLETE, SESSION_USER_LIGHT, SESSION_USER_EARLY_LIGHT, \
|
||||
SESSION_GREETER, SESSION_LOCK_SCREEN, SESSION_BACKGROUND, SESSION_BACKGROUND_LIGHT)
|
||||
|
||||
/* Which session classes want their own per-user service manager? */
|
||||
#define SESSION_CLASS_WANTS_SERVICE_MANAGER(class) IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_GREETER, SESSION_LOCK_SCREEN, SESSION_BACKGROUND)
|
||||
@ -48,25 +52,25 @@ typedef enum SessionClass {
|
||||
#define SESSION_CLASS_PIN_USER(class) (!IN_SET((class), SESSION_MANAGER, SESSION_MANAGER_EARLY, SESSION_NONE))
|
||||
|
||||
/* Which session classes decide whether system is idle? (should only cover sessions that have input, and are not idle screens themselves)*/
|
||||
#define SESSION_CLASS_CAN_IDLE(class) (IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_GREETER))
|
||||
#define SESSION_CLASS_CAN_IDLE(class) (IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_USER_EARLY_LIGHT, SESSION_USER_LIGHT, SESSION_GREETER))
|
||||
|
||||
/* Which session classes have a lock screen concept? */
|
||||
#define SESSION_CLASS_CAN_LOCK(class) (IN_SET((class), SESSION_USER, SESSION_USER_EARLY))
|
||||
#define SESSION_CLASS_CAN_LOCK(class) (IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_USER_EARLY_LIGHT, SESSION_USER_LIGHT))
|
||||
|
||||
/* Which sessions are candidates to become "display" sessions */
|
||||
#define SESSION_CLASS_CAN_DISPLAY(class) (IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_GREETER))
|
||||
#define SESSION_CLASS_CAN_DISPLAY(class) (IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_USER_EARLY_LIGHT, SESSION_USER_LIGHT, SESSION_GREETER))
|
||||
|
||||
/* Which sessions classes should be subject to stop-in-idle */
|
||||
#define SESSION_CLASS_CAN_STOP_ON_IDLE(class) (IN_SET((class), SESSION_USER, SESSION_USER_EARLY))
|
||||
#define SESSION_CLASS_CAN_STOP_ON_IDLE(class) (IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_USER_LIGHT, SESSION_USER_EARLY_LIGHT))
|
||||
|
||||
/* Which session classes can take control of devices */
|
||||
#define SESSION_CLASS_CAN_TAKE_DEVICE(class) (IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_GREETER, SESSION_LOCK_SCREEN))
|
||||
#define SESSION_CLASS_CAN_TAKE_DEVICE(class) (IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_USER_LIGHT, SESSION_USER_EARLY_LIGHT, SESSION_GREETER, SESSION_LOCK_SCREEN))
|
||||
|
||||
/* Which session classes allow changing session types */
|
||||
#define SESSION_CLASS_CAN_CHANGE_TYPE(class) (IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_GREETER, SESSION_LOCK_SCREEN))
|
||||
#define SESSION_CLASS_CAN_CHANGE_TYPE(class) (IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_USER_LIGHT, SESSION_USER_EARLY_LIGHT, SESSION_GREETER, SESSION_LOCK_SCREEN))
|
||||
|
||||
/* Which session classes are taken into acccount when deciding whether shutdown shall be allowed if other users are logged in */
|
||||
#define SESSION_CLASS_IS_INHIBITOR_LIKE(class) IN_SET((class), SESSION_USER, SESSION_USER_EARLY)
|
||||
#define SESSION_CLASS_IS_INHIBITOR_LIKE(class) IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_USER_LIGHT, SESSION_USER_EARLY_LIGHT)
|
||||
|
||||
typedef enum SessionType {
|
||||
SESSION_UNSPECIFIED,
|
||||
|
@ -1006,14 +1006,36 @@ static void session_context_mangle(
|
||||
c->vtnr = 0;
|
||||
}
|
||||
|
||||
if (isempty(c->type))
|
||||
if (isempty(c->type)) {
|
||||
c->type = !isempty(c->display) ? "x11" :
|
||||
!isempty(c->tty) ? "tty" : "unspecified";
|
||||
pam_debug_syslog(handle, debug, "Automatically chose session type '%s'.", c->type);
|
||||
}
|
||||
|
||||
if (isempty(c->class))
|
||||
c->class = streq(c->type, "unspecified") ? "background" :
|
||||
((IN_SET(user_record_disposition(ur), USER_INTRINSIC, USER_SYSTEM, USER_DYNAMIC) &&
|
||||
streq(c->type, "tty")) ? "user-early" : "user");
|
||||
if (isempty(c->class)) {
|
||||
c->class = streq(c->type, "unspecified") ? "background" : "user";
|
||||
|
||||
/* For non-regular users tweak the type a bit:
|
||||
*
|
||||
* - Allow root tty logins *before* systemd-user-sessions.service is run, to allow early boot
|
||||
* logins to debug things.
|
||||
*
|
||||
* - Non-graphical sessions shall be invoked without service manager.
|
||||
*
|
||||
* (Note that this somewhat replicates the class mangling logic on systemd-logind.service's
|
||||
* server side to some degree, in case clients allocate a session and don't specify a
|
||||
* class. This is somewhat redundant, but we need the class set up properly below.) */
|
||||
|
||||
if (IN_SET(user_record_disposition(ur), USER_INTRINSIC, USER_SYSTEM, USER_DYNAMIC)) {
|
||||
if (streq(c->class, "user"))
|
||||
c->class = user_record_is_root(ur) ? "user-early" :
|
||||
(STR_IN_SET(c->type, "x11", "wayland", "mir") ? "user" : "user-light");
|
||||
else if (streq(c->class, "background"))
|
||||
c->class = "background-light";
|
||||
}
|
||||
|
||||
pam_debug_syslog(handle, debug, "Automatically chose session class '%s'.", c->class);
|
||||
}
|
||||
|
||||
if (c->incomplete) {
|
||||
if (streq(c->class, "user"))
|
||||
|
@ -21,6 +21,10 @@ static SD_VARLINK_DEFINE_ENUM_TYPE(
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(user_early),
|
||||
SD_VARLINK_FIELD_COMMENT("Regular user session whose home directory is not available right now, but will be later, at which point the session class can be upgraded to 'user'"),
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(user_incomplete),
|
||||
SD_VARLINK_FIELD_COMMENT("A user session that doesn't pull in the per-user service manager"),
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(user_light),
|
||||
SD_VARLINK_FIELD_COMMENT("The combination of user_early and user_light"),
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(user_early_light),
|
||||
SD_VARLINK_FIELD_COMMENT("Display manager greeter screen used for login"),
|
||||
SD_VARLINK_DEFINE_ENUM_VALUE(greeter),
|
||||
SD_VARLINK_FIELD_COMMENT("Similar, but a a lock screen"),
|
||||
|
@ -711,6 +711,8 @@ testcase_background() {
|
||||
TRANSIENTUNIT0="none$RANDOM.service"
|
||||
TRANSIENTUNIT1="bg$RANDOM.service"
|
||||
TRANSIENTUNIT2="bgg$RANDOM.service"
|
||||
TRANSIENTUNIT3="bggg$RANDOM.service"
|
||||
TRANSIENTUNIT4="bgggg$RANDOM.service"
|
||||
|
||||
trap background_at_return RETURN
|
||||
|
||||
@ -745,6 +747,17 @@ EOF
|
||||
systemctl stop "$TRANSIENTUNIT2"
|
||||
|
||||
systemctl stop user@"$uid".service
|
||||
|
||||
# Now check that system users automatically get the light session class assigned
|
||||
systemd-sysusers --inline "u lightuser"
|
||||
|
||||
systemd-run -u "$TRANSIENTUNIT3" -p PAMName="$PAMSERVICE" -p "Environment=XDG_SESSION_TYPE=unspecified" -p Type=exec -p User=lightuser sleep infinity
|
||||
loginctl | grep lightuser | grep -q background-light
|
||||
systemctl stop "$TRANSIENTUNIT3"
|
||||
|
||||
systemd-run -u "$TRANSIENTUNIT4" -p PAMName="$PAMSERVICE" -p "Environment=XDG_SESSION_TYPE=tty" -p Type=exec -p User=lightuser sleep infinity
|
||||
loginctl | grep lightuser | grep -q user-light
|
||||
systemctl stop "$TRANSIENTUNIT4"
|
||||
}
|
||||
|
||||
testcase_varlink() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user