The code was of two minds about error_id: it was used directly in
pam_syslog_errno(), but in the next line checked with streq_ptr().
sd_varlink_callbo() may return negative and then it does not set the output
params, or it returns the error in ret_error_id. We cannot assume that error_id
is non-null. Also fix a select-and-paste mistake in one place.
Follow-up for cfb7abc7fc
For whatever reason, ly is setting $XDG_RUNTIME_DIR before invoking
PAM session on its own
(https://github.com/fairyglade/ly/blob/v1.1.1/src/auth.zig#L45),
which after the offending commit will potentially be unset again
by pam_systemd. Let's restore the previous behavior if not switching area.
Fixes#38402
Traditionally, logind installed a fifo in the PAM session and
used EOF on the fd as signal for session close. With the addition of
pidfd (76f2191d8e) however,
logind tracks the leader process and the session is terminated
as soon as that exits. I think the new behavior generally makes
more sense, and the behavior got changed *in the mentioned commit
already* without anyone ever showing up to complain. It hence
feels safe to kill the concept now (also before the varlink interface
gets rolled out).
Note that the 'PID' field in CreateSession() Varlink method
is now marked as strict, i.e. failure to acquire pidfd
is immediately treated as fatal.
userdb allows user/group records without UID/GID (it only really
requires a name), in order to permit "unfixated" records. But that means
we cannot just rely on the field to be valid. And we mostly got that
right, but not everywhere. Fix that.
We currently don't support invoking a per-area service manager instance,
hence don't try to pull in one if we log into an area.
Once we add support for per-area service managers we can relax this
again.
note: this also adds making a copy of the session type string after
registering the session. That's because we need to check the session
type we settled on later to condition out the OSC sequence (because it
should only be issued on TTY sessions). However, the session type string
originally quite likely points into the PAM environment block, which we
update in the meantime, invalidating that pointer. hence, make an
explicit copy first, and use that.
When a user logs into a non-default area we give them a private
$HOME for that area (that's what 'area' is supposed to be after all). We
so far left $XDG_RUNTIME_DIRECTORY as it was. Let's change that and
mirror the subdirectory logic there too.
Why? $XDG_RUNTIME_DIR is generally the place where AF_UNIX sockets are
bound that can be used to connect to per-user services. (in particular
all those which are behind D-Bus.) If we don't patch $XDG_RUNTIME_DIR
like this then this means all the backing services will use the main
area, which is problematic (since clients and services will disagree on
$HOME), and makes it impossible to support the area concept for
graphical logins properly.
This does not actually make graphical logins work, but it at least makes
them fail cleanly. That's because this patch alone won't make sure a
per-area service manager/dbus instance is invoked automatically. That
however can be added later, in a patch to logind.
Let's tweak update_environment() a bit: instead of being a NOP when no
value is specified, let's actively unset the specified environment
variable if it is set.
This shouldn't change much, since for the cases we call the function so
far the env vars in question should not be set before us in a way we'd
set them differently. However, this is nice preparation for later, as we
can make use of this for XDG_AREA which we might want to unset if we
consider the area dir invalid.
This moves around the UserDBMatch handling, moves it out of userdbctl
and into generic userdb code, so that it can be passed to the server
side, to allow server side filtering.
This is preparation for one day allowing complex software to do such
filtering server side, and thus reducing the necessary traffic.
Right now no server side actually knows this, hence care is taken to
downgrade to the userdb varlink API as it was in v257 in case the new
options are not understood. This retains compatibility with any
implementation hence.
This in particular makes sure that we normalize the user name and update
it in the PAM session, once we acquire it. This means that if you have a
user with name "a" and alias "b", and the user logs in as "b" they end
up properly with "a" as user name set, as intended by the PAM gods.
Moreover, if you have a user "c" in a ralm "d", they may log in by
specifying "c" or "c@d", with equivalent results.
This ensures that user names can be specified either in the regular
short syntax or with a realm appended, and both are accepted. (The
latter of course only if the record actually defines a realm)
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 makes sure we now use Varlink per default as transport for
allocating sessions.
This reduces the time it takes to do one run0 cycle by roughly ~10% on my
completely synthetic test setup (assuming the target user's service
manager is already started)
The D-Bus codepaths are kept in place for two reasons:
* To make upgrades easy
* If the user actually sets resource properties on the PAM session we
fall back to the D-Bus codepaths, as we currently have no way to
encode the scope properties in JSON, this is only supported for D-Bus
serialization.
The latter should be revisited once it is possible to allocate a scope
unit from PID1 via varlink.
pam_systemd is used to create logind sessions and to apply extended
attributes from json user records. Not every application that creates a
pam session expects a login scope, but may be interested in the extended
attributes of json user records. Session class "none" implements this
service by disabling logind for this session altogether.
We got confused by the error codes here, and sometimes return PAM errors
where the caller propagated them unconverted as negative errno errors. Fix that.
Let's separate four different parts of pam_sm_open_session():
1. Acquiring of our various parameters from pam env, pam data, pam items
2. Mangling of that data to clean it up
3. Registering of the service with logind
4. Importing shell credentials into environment variables
5. Enforcement of user record data
This makes the code a lot more readable, and gets rid of an ugly goto
label.
It also corrects things: if step 3 doesnt work because logind is not
around, we'll now still do step 4, which we previously erroneously
skipped.
Besides that no real code changes.
Let's shorten the code of pam_sm_open_session() a bit, and also make
sure the importing of the env vars from the creds also happens if the
session registration with logind is skipped.
Let's instead just pass over the UserRecord, it's a much more useful
object with lots more information we'll sooner or later need
(preparation for later commits).
We never use the field and this is not going to change...
This addresses a weird asymmetry, as create_session_message() always
went to the process' own PID when doing pidfds but otherwise (i.e.
without pidfds) would honour the PID specified as function parameter.
This is preparation for making our Varlink API a public API. Since our
Varlink API is built on top of our JSON API we need to make that public
first (it's a nice API, but JSON APIs there are already enough, this is
purely about the Varlink angle).
I made most of the json.h APIs public, and just placed them in
sd-json.h. Sometimes I wasn't so sure however, since the underlying data
structures would have to be made public too. If in doubt I didn#t risk
it, and moved the relevant API to src/libsystemd/sd-json/json-util.h
instead (without any sd_* symbol prefixes).
This is mostly a giant search/replace patch.
We already log to syslog using pam_syslog() for logs generated directly
within our pam plugins. However, any logs generated by our generic logging
macros that are invoked within a pam plugin will log to the console. Let's
make sure our generic logging macros are set up to log to syslog as well.
Skip using pidfds if we get a permission denied error.
This can happen with an old policy and a new kernel that uses the
new pidfs filesystem to back pidfds, instead of anonymous inodes,
as the existing policy denies access.
This is already the case for most uses of pidfd_open, like pidref,
but not on these two. Fix them.
This allows earlier PAM modules (i.e. pam_systemd_home) to inform
pam_systemd that the session is not "complete" yet (i.e. doesn't have
the home dir set up properly yet).
This field is like preferredLanguage, but takes a priority list of
languages instead. If an app isn't translated into a user's primary
language, it can fall back to one of the other languages in the list
thus making the app more accessible to the user.
For instance: in my experience, many Ukrainians are fluent in Russian,
often significantly better than English (especially if they are of a
generation that grew up during the USSR). Such a person might set this
new variable to ["uk_UA.UTF-8", "ru_UA.UTF-8"] so that software that
lacks Ukrainian translations will first try Russian translations before
defaulting to English.
Fixes#31290
The user record should be the source of truth for the user's environment
variables, and the user should be able to override them in much the same
way that they can if they simply append the variable to their ~/.profile
For example, before $LANG would never get set to the user's preferred
language, because the service manager always ensures that $LANG is set
to something (either the localed config, or a compiled-in default). Thus
the user's preferredLanguage setting was always ignored