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
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.
<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>
</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>
<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>
const char *remote_host,
Session **ret_session) {
+ bool mangle_class = false;
int r;
assert(m);
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. */
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;
[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",
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 */
/* 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)
#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,
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" : "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";
+ }
- 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");
+ pam_debug_syslog(handle, debug, "Automatically chose session class '%s'.", c->class);
+ }
if (c->incomplete) {
if (streq(c->class, "user"))
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"),
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
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() {