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