mirror of
https://github.com/systemd/systemd.git
synced 2025-03-23 10:50:16 +03:00
pam-systemd: introduce "user-light" session type, and make "background-light" the default for system users (#35987)
This implements one idea from #34988: default to "user-light" and "background-light" for system users, so that the service manager is only pulled in for sessions that likely need them, i.e. not cron jobs or ftp logins. This is a compat break to some degree, but I think a worthy one. I updated the NEWS file to explain this.
This commit is contained in:
commit
f8214e2cca
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>
|
||||
|
16
man/run0.xml
16
man/run0.xml
@ -224,6 +224,21 @@
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--lightweight=<replaceable>BOOLEAN</replaceable></option></term>
|
||||
|
||||
<listitem><para>Controls whether to activate the per-user service manager for the target user. By
|
||||
default if the target user is <literal>root</literal> or a system user the per-user service manager
|
||||
is not activated as effect of the <command>run0</command> invocation, otherwise it is.</para>
|
||||
|
||||
<para>This ultimately controls the <varname>$XDG_SESSION_CLASS</varname> variable
|
||||
<citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry>
|
||||
respects.</para>
|
||||
|
||||
<xi:include href="version-info.xml" xpointer="v258"/>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term><option>--machine=</option></term>
|
||||
|
||||
@ -321,6 +336,7 @@
|
||||
<member><citerefentry><refentrytitle>systemd-run</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry project='man-pages'><refentrytitle>sudo</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>machinectl</refentrytitle><manvolnum>1</manvolnum></citerefentry></member>
|
||||
<member><citerefentry><refentrytitle>pam_systemd</refentrytitle><manvolnum>8</manvolnum></citerefentry></member>
|
||||
</simplelist></para>
|
||||
</refsect1>
|
||||
|
||||
|
@ -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;
|
||||
@ -1835,7 +1859,7 @@ static int have_multiple_sessions(
|
||||
/* Check for other users' sessions. Greeter sessions do not
|
||||
* count, and non-login sessions do not count either. */
|
||||
HASHMAP_FOREACH(session, m->sessions)
|
||||
if (IN_SET(session->class, SESSION_USER, SESSION_USER_EARLY) &&
|
||||
if (SESSION_CLASS_IS_INHIBITOR_LIKE(session->class) &&
|
||||
session->user->user_record->uid != uid)
|
||||
return true;
|
||||
|
||||
|
@ -859,7 +859,13 @@ int session_start(Session *s, sd_bus_message *properties, sd_bus_error *error) {
|
||||
"SESSION_ID=%s", s->id,
|
||||
"USER_ID=%s", s->user->user_record->user_name,
|
||||
"LEADER="PID_FMT, s->leader.pid,
|
||||
LOG_MESSAGE("New session %s of user %s.", s->id, s->user->user_record->user_name));
|
||||
"CLASS=%s", session_class_to_string(s->class),
|
||||
"TYPE=%s", session_type_to_string(s->type),
|
||||
LOG_MESSAGE("New session '%s' of user '%s' with class '%s' and type '%s'.",
|
||||
s->id,
|
||||
s->user->user_record->user_name,
|
||||
session_class_to_string(s->class),
|
||||
session_type_to_string(s->type)));
|
||||
|
||||
if (!dual_timestamp_is_set(&s->timestamp))
|
||||
dual_timestamp_now(&s->timestamp);
|
||||
@ -1704,6 +1710,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,22 +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, SESSION_USER_LIGHT, SESSION_USER_EARLY_LIGHT)
|
||||
|
||||
typedef enum SessionType {
|
||||
SESSION_UNSPECIFIED,
|
||||
|
@ -755,7 +755,7 @@ static int apply_user_record_settings(
|
||||
|
||||
if (nice_is_valid(ur->nice_level)) {
|
||||
if (nice(ur->nice_level) < 0)
|
||||
pam_syslog_errno(handle, LOG_ERR, errno,
|
||||
pam_syslog_errno(handle, LOG_WARNING, errno,
|
||||
"Failed to set nice level to %i, ignoring: %m", ur->nice_level);
|
||||
else
|
||||
pam_debug_syslog(handle, debug,
|
||||
@ -763,7 +763,6 @@ static int apply_user_record_settings(
|
||||
}
|
||||
|
||||
for (int rl = 0; rl < _RLIMIT_MAX; rl++) {
|
||||
|
||||
if (!ur->rlimits[rl])
|
||||
continue;
|
||||
|
||||
@ -1007,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"))
|
||||
|
130
src/run/run.c
130
src/run/run.c
@ -88,6 +88,7 @@ static bool arg_ignore_failure = false;
|
||||
static char *arg_background = NULL;
|
||||
static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF;
|
||||
static char *arg_shell_prompt_prefix = NULL;
|
||||
static int arg_lightweight = -1;
|
||||
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_description, freep);
|
||||
STATIC_DESTRUCTOR_REGISTER(arg_environment, strv_freep);
|
||||
@ -199,6 +200,8 @@ static int help_sudo_mode(void) {
|
||||
" --pty Request allocation of a pseudo TTY for stdio\n"
|
||||
" --pipe Request direct pipe for stdio\n"
|
||||
" --shell-prompt-prefix=PREFIX Set $SHELL_PROMPT_PREFIX\n"
|
||||
" --lightweight=BOOLEAN Control whether to register a session with service manager\n"
|
||||
" or without\n"
|
||||
"\nSee the %s for details.\n",
|
||||
program_invocation_short_name,
|
||||
ansi_highlight(),
|
||||
@ -778,6 +781,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
ARG_PTY,
|
||||
ARG_PIPE,
|
||||
ARG_SHELL_PROMPT_PREFIX,
|
||||
ARG_LIGHTWEIGHT,
|
||||
};
|
||||
|
||||
/* If invoked as "run0" binary, let's expose a more sudo-like interface. We add various extensions
|
||||
@ -802,6 +806,7 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
{ "pty", no_argument, NULL, ARG_PTY },
|
||||
{ "pipe", no_argument, NULL, ARG_PIPE },
|
||||
{ "shell-prompt-prefix", required_argument, NULL, ARG_SHELL_PROMPT_PREFIX },
|
||||
{ "lightweight", required_argument, NULL, ARG_LIGHTWEIGHT },
|
||||
{},
|
||||
};
|
||||
|
||||
@ -914,6 +919,12 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
return r;
|
||||
break;
|
||||
|
||||
case ARG_LIGHTWEIGHT:
|
||||
r = parse_tristate_argument("--lightweight=", optarg, &arg_lightweight);
|
||||
if (r < 0)
|
||||
return r;
|
||||
break;
|
||||
|
||||
case '?':
|
||||
return -EINVAL;
|
||||
|
||||
@ -947,6 +958,8 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
if (IN_SET(arg_stdio, ARG_STDIO_NONE, ARG_STDIO_AUTO))
|
||||
arg_stdio = isatty_safe(STDIN_FILENO) && isatty_safe(STDOUT_FILENO) && isatty_safe(STDERR_FILENO) ? ARG_STDIO_PTY : ARG_STDIO_DIRECT;
|
||||
|
||||
log_debug("Using %s stdio mode.", arg_stdio == ARG_STDIO_PTY ? "pty" : "direct");
|
||||
|
||||
arg_expand_environment = false;
|
||||
arg_send_sighup = true;
|
||||
|
||||
@ -1045,6 +1058,28 @@ static int parse_argv_sudo_mode(int argc, char *argv[]) {
|
||||
return log_error_errno(r, "Failed to set $SHELL_PROMPT_PREFIX environment variable: %m");
|
||||
}
|
||||
|
||||
/* When using run0 to acquire privileges temporarily, let's not pull in session manager by
|
||||
* default. Note that pam_logind/systemd-logind doesn't distinguish between run0-style privilege
|
||||
* escalation on a TTY and first class (getty-style) TTY logins (and thus gives root a per-session
|
||||
* manager for interactive TTY sessions), hence let's override the logic explicitly here. We only do
|
||||
* this for root though, under the assumption that if a regular user temporarily transitions into
|
||||
* another regular user it's a better default that the full user environment is uniformly
|
||||
* available. */
|
||||
if (arg_lightweight < 0 && !strv_env_get(arg_environment, "XDG_SESSION_CLASS") && privileged_execution())
|
||||
arg_lightweight = true;
|
||||
|
||||
if (arg_lightweight >= 0) {
|
||||
const char *class =
|
||||
arg_lightweight ? (arg_stdio == ARG_STDIO_PTY ? (privileged_execution() ? "user-early-light" : "user-light") : "background-light") :
|
||||
(arg_stdio == ARG_STDIO_PTY ? (privileged_execution() ? "user-early" : "user") : "background");
|
||||
|
||||
log_debug("Setting XDG_SESSION_CLASS to '%s'.", class);
|
||||
|
||||
r = strv_env_assign(&arg_environment, "XDG_SESSION_CLASS", class);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to set $XDG_SESSION_CLASS environment variable: %m");
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@ -1901,6 +1936,46 @@ static int print_unit_invocation(const char *unit, sd_id128_t invocation_id) {
|
||||
return sd_json_variant_dump(v, arg_json_format_flags, stdout, NULL);
|
||||
}
|
||||
|
||||
typedef struct JobDoneContext {
|
||||
char *unit;
|
||||
char *start_job;
|
||||
sd_bus_slot *match;
|
||||
} JobDoneContext;
|
||||
|
||||
static void job_done_context_done(JobDoneContext *c) {
|
||||
assert(c);
|
||||
|
||||
c->unit = mfree(c->unit);
|
||||
c->start_job = mfree(c->start_job);
|
||||
c->match = sd_bus_slot_unref(c->match);
|
||||
}
|
||||
|
||||
static int match_job_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
|
||||
JobDoneContext *c = ASSERT_PTR(userdata);
|
||||
const char *path;
|
||||
int r;
|
||||
|
||||
assert(m);
|
||||
|
||||
r = sd_bus_message_read(m, "uoss", /* id = */ NULL, &path, /* unit= */ NULL, /* result= */ NULL);
|
||||
if (r < 0) {
|
||||
bus_log_parse_error(r);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!streq_ptr(path, c->start_job))
|
||||
return 0;
|
||||
|
||||
/* Notify our caller that the service is now running, just in case. */
|
||||
(void) sd_notifyf(/* unset_environment= */ false,
|
||||
"READY=1\n"
|
||||
"RUN_UNIT=%s",
|
||||
c->unit);
|
||||
|
||||
job_done_context_done(c);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int start_transient_service(sd_bus *bus) {
|
||||
_cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
|
||||
_cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
|
||||
@ -1974,16 +2049,6 @@ static int start_transient_service(sd_bus *bus) {
|
||||
assert_not_reached();
|
||||
}
|
||||
|
||||
/* Optionally, wait for the start job to complete. If we are supposed to read the service's stdin
|
||||
* lets skip this however, because we should start that already when the start job is running, and
|
||||
* there's little point in waiting for the start job to complete in that case anyway, as we'll wait
|
||||
* for EOF anyway, which is going to be much later. */
|
||||
if (!arg_no_block && arg_stdio == ARG_STDIO_NONE) {
|
||||
r = bus_wait_for_jobs_new(bus, &w);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not watch jobs: %m");
|
||||
}
|
||||
|
||||
if (arg_unit) {
|
||||
r = unit_name_mangle_with_suffix(arg_unit, "as unit",
|
||||
arg_quiet ? 0 : UNIT_NAME_MANGLE_WARN,
|
||||
@ -1996,6 +2061,36 @@ static int start_transient_service(sd_bus *bus) {
|
||||
return r;
|
||||
}
|
||||
|
||||
/* Optionally, wait for the start job to complete. If we are supposed to read the service's stdin
|
||||
* lets skip this however, because we should start that already when the start job is running, and
|
||||
* there's little point in waiting for the start job to complete in that case anyway, as we'll wait
|
||||
* for EOF anyway, which is going to be much later. */
|
||||
_cleanup_(job_done_context_done) JobDoneContext job_done_context = {};
|
||||
if (!arg_no_block) {
|
||||
if (arg_stdio == ARG_STDIO_NONE) {
|
||||
r = bus_wait_for_jobs_new(bus, &w);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Could not watch jobs: %m");
|
||||
} else {
|
||||
job_done_context.unit = strdup(service);
|
||||
if (!job_done_context.unit)
|
||||
return log_oom();
|
||||
|
||||
/* When we are a bus client we match by sender. Direct connections OTOH have no
|
||||
* initialized sender field, and hence we ignore the sender then */
|
||||
r = sd_bus_match_signal_async(
|
||||
bus,
|
||||
&job_done_context.match,
|
||||
sd_bus_is_bus_client(bus) ? "org.freedesktop.systemd1" : NULL,
|
||||
"/org/freedesktop/systemd1",
|
||||
"org.freedesktop.systemd1.Manager",
|
||||
"JobRemoved",
|
||||
match_job_removed, NULL, &job_done_context);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to install JobRemove match: %m");
|
||||
}
|
||||
}
|
||||
|
||||
r = make_transient_service_unit(bus, &m, service, pty_path, peer_fd);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@ -2005,19 +2100,22 @@ static int start_transient_service(sd_bus *bus) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
const char *object;
|
||||
r = sd_bus_message_read(reply, "o", &object);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
if (w) {
|
||||
const char *object;
|
||||
|
||||
r = sd_bus_message_read(reply, "o", &object);
|
||||
if (r < 0)
|
||||
return bus_log_parse_error(r);
|
||||
|
||||
r = bus_wait_for_jobs_one(w,
|
||||
object,
|
||||
arg_quiet ? 0 : BUS_WAIT_JOBS_LOG_ERROR,
|
||||
arg_runtime_scope == RUNTIME_SCOPE_USER ? STRV_MAKE_CONST("--user") : NULL);
|
||||
if (r < 0)
|
||||
return r;
|
||||
} else if (job_done_context.match) {
|
||||
job_done_context.start_job = strdup(object);
|
||||
if (!job_done_context.start_job)
|
||||
return log_oom();
|
||||
}
|
||||
|
||||
if (!arg_quiet) {
|
||||
|
@ -31,6 +31,26 @@ int parse_boolean_argument(const char *optname, const char *s, bool *ret) {
|
||||
}
|
||||
}
|
||||
|
||||
int parse_tristate_argument(const char *optname, const char *s, int *ret) {
|
||||
int r;
|
||||
|
||||
if (s) {
|
||||
r = parse_boolean(s);
|
||||
if (r < 0)
|
||||
return log_error_errno(r, "Failed to parse boolean argument to %s: %s.", optname, s);
|
||||
|
||||
if (ret)
|
||||
*ret = r;
|
||||
|
||||
return r;
|
||||
} else {
|
||||
if (ret)
|
||||
*ret = -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int parse_json_argument(const char *s, sd_json_format_flags_t *ret) {
|
||||
assert(s);
|
||||
assert(ret);
|
||||
|
@ -6,6 +6,7 @@
|
||||
#include "sd-json.h"
|
||||
|
||||
int parse_boolean_argument(const char *optname, const char *s, bool *ret);
|
||||
int parse_tristate_argument(const char *optname, const char *s, int *ret);
|
||||
int parse_json_argument(const char *s, sd_json_format_flags_t *ret);
|
||||
int parse_path_argument(const char *path, bool suppress_root, char **arg);
|
||||
int parse_signal_argument(const char *s, int *ret);
|
||||
|
@ -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,12 @@ testcase_background() {
|
||||
TRANSIENTUNIT0="none$RANDOM.service"
|
||||
TRANSIENTUNIT1="bg$RANDOM.service"
|
||||
TRANSIENTUNIT2="bgg$RANDOM.service"
|
||||
TRANSIENTUNIT3="bggg$RANDOM.service"
|
||||
TRANSIENTUNIT4="bgggg$RANDOM.service"
|
||||
RUN0UNIT0="run0$RANDOM.service"
|
||||
RUN0UNIT1="runn0$RANDOM.service"
|
||||
RUN0UNIT2="runnn0$RANDOM.service"
|
||||
RUN0UNIT3="runnnn0$RANDOM.service"
|
||||
|
||||
trap background_at_return RETURN
|
||||
|
||||
@ -745,6 +751,34 @@ 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"
|
||||
|
||||
# Now check that run0's session class control works
|
||||
systemd-run --service-type=notify run0 -u lightuser --unit="$RUN0UNIT0" sleep infinity
|
||||
loginctl | grep lightuser | grep -q "background-light "
|
||||
systemctl stop "$RUN0UNIT0"
|
||||
|
||||
systemd-run --service-type=notify run0 -u lightuser --unit="$RUN0UNIT1" --lightweight=yes sleep infinity
|
||||
loginctl | grep lightuser | grep -q "background-light "
|
||||
systemctl stop "$RUN0UNIT1"
|
||||
|
||||
systemd-run --service-type=notify run0 -u lightuser --unit="$RUN0UNIT2" --lightweight=no sleep infinity
|
||||
loginctl | grep lightuser | grep -q "background "
|
||||
systemctl stop "$RUN0UNIT2"
|
||||
|
||||
systemd-run --service-type=notify run0 -u root --unit="$RUN0UNIT3" sleep infinity
|
||||
loginctl | grep root | grep -q "background-light "
|
||||
systemctl stop "$RUN0UNIT3"
|
||||
}
|
||||
|
||||
testcase_varlink() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user