diff --git a/man/pam_systemd.xml b/man/pam_systemd.xml
index 33d02c4efb..18c3636b6b 100644
--- a/man/pam_systemd.xml
+++ b/man/pam_systemd.xml
@@ -143,6 +143,10 @@
manager-early
Similar to manager, but for the root user. Compare with the user vs. user-early situation. (Added in v256.)
+
+ none
+ Skips registering this session with logind. No session scope will be created, and the user service manager will not be started. (Added in v258.)
+
diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c
index 56531a22f6..9ffaf8888c 100644
--- a/src/login/logind-dbus.c
+++ b/src/login/logind-dbus.c
@@ -911,6 +911,27 @@ static int create_session(
if (!uid_is_valid(uid))
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid UID");
+ if (isempty(type))
+ t = _SESSION_TYPE_INVALID;
+ else {
+ t = session_type_from_string(type);
+ if (t < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+ "Invalid session type %s", type);
+ }
+
+ if (isempty(class))
+ c = _SESSION_CLASS_INVALID;
+ else {
+ c = session_class_from_string(class);
+ if (c < 0)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+ "Invalid session class %s", class);
+ if (c == SESSION_NONE)
+ return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
+ "Refusing session class %s", class);
+ }
+
if (flags != 0)
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Flags must be zero.");
@@ -930,24 +951,6 @@ static int create_session(
if (leader.pid == 1 || pidref_is_self(&leader))
return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
- if (isempty(type))
- t = _SESSION_TYPE_INVALID;
- else {
- t = session_type_from_string(type);
- if (t < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
- "Invalid session type %s", type);
- }
-
- if (isempty(class))
- c = _SESSION_CLASS_INVALID;
- else {
- c = session_class_from_string(class);
- if (c < 0)
- return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS,
- "Invalid session class %s", class);
- }
-
if (isempty(desktop))
desktop = NULL;
else {
diff --git a/src/login/logind-session.c b/src/login/logind-session.c
index 351b64b60b..ed93fd7d9e 100644
--- a/src/login/logind-session.c
+++ b/src/login/logind-session.c
@@ -1678,6 +1678,7 @@ static const char* const session_class_table[_SESSION_CLASS_MAX] = {
[SESSION_BACKGROUND_LIGHT] = "background-light",
[SESSION_MANAGER] = "manager",
[SESSION_MANAGER_EARLY] = "manager-early",
+ [SESSION_NONE] = "none",
};
DEFINE_STRING_TABLE_LOOKUP(session_class, SessionClass);
diff --git a/src/login/logind-session.h b/src/login/logind-session.h
index 2d2cb189fc..f7ee7a92b6 100644
--- a/src/login/logind-session.h
+++ b/src/login/logind-session.h
@@ -29,6 +29,7 @@ typedef enum SessionClass {
SESSION_BACKGROUND_LIGHT, /* Like SESSION_BACKGROUND, but without the service manager */
SESSION_MANAGER, /* The service manager */
SESSION_MANAGER_EARLY, /* The service manager for root (which is allowed to run before systemd-user-sessions.service) */
+ SESSION_NONE, /* A session not registered with logind */
_SESSION_CLASS_MAX,
_SESSION_CLASS_INVALID = -EINVAL,
} SessionClass;
@@ -44,7 +45,7 @@ typedef enum SessionClass {
#define SESSION_CLASS_WANTS_SERVICE_MANAGER(class) IN_SET((class), SESSION_USER, SESSION_USER_EARLY, SESSION_GREETER, SESSION_LOCK_SCREEN, SESSION_BACKGROUND)
/* Which session classes can pin our user tracking? */
-#define SESSION_CLASS_PIN_USER(class) (!IN_SET((class), SESSION_MANAGER, SESSION_MANAGER_EARLY))
+#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))
diff --git a/src/login/pam_systemd.c b/src/login/pam_systemd.c
index 9d96c91539..e0861f934c 100644
--- a/src/login/pam_systemd.c
+++ b/src/login/pam_systemd.c
@@ -1043,6 +1043,12 @@ static int register_session(
assert(ur);
assert(ret_seat);
+ /* We don't register session class none with logind */
+ if (streq(c->class, "none")) {
+ pam_debug_syslog(handle, debug, "Skipping logind registration for session class none");
+ goto skip;
+ }
+
/* Make most of this a NOP on non-logind systems */
if (!logind_running())
goto skip;
diff --git a/test/units/TEST-35-LOGIN.sh b/test/units/TEST-35-LOGIN.sh
index 80320e32e1..1fc49e75b4 100755
--- a/test/units/TEST-35-LOGIN.sh
+++ b/test/units/TEST-35-LOGIN.sh
@@ -701,13 +701,14 @@ background_at_return() {
testcase_background() {
- local uid TRANSIENTUNIT1 TRANSIENTUNIT2
+ local uid TRANSIENTUNIT0 TRANSIENTUNIT1 TRANSIENTUNIT2
uid=$(id -u logind-test-user)
systemctl stop user@"$uid".service
PAMSERVICE="pamserv$RANDOM"
+ TRANSIENTUNIT0="none$RANDOM.service"
TRANSIENTUNIT1="bg$RANDOM.service"
TRANSIENTUNIT2="bgg$RANDOM.service"
@@ -722,6 +723,13 @@ session optional pam_systemd.so debug
session required pam_unix.so
EOF
+ systemd-run -u "$TRANSIENTUNIT0" -p PAMName="$PAMSERVICE" -p "Environment=XDG_SESSION_CLASS=none" -p Type=exec -p User=logind-test-user sleep infinity
+
+ # This was a 'none' service, so logind should take no action
+ (! systemctl is-active user@"$uid".service )
+
+ systemctl stop "$TRANSIENTUNIT0"
+
systemd-run -u "$TRANSIENTUNIT1" -p PAMName="$PAMSERVICE" -p "Environment=XDG_SESSION_CLASS=background-light" -p Type=exec -p User=logind-test-user sleep infinity
# This was a 'light' background service, hence the service manager should not be running