homed maintains two or three copies of the user's identity record per
home directory: one on the host, one inside the LUKS header, and one
embedded in the home directory.
Previously we'd insist that if a user logs in they have to authenticate
against all three, as a safety feature. This broke logging into
unfixated records however, since in that case the host version is
synthetic and thus does not carry any authentication data.
Let's hence losen the strictness here: accept authentication against
host records that carry no auth data. This should be safe as we know
after all that the second/third record will catch invalid accesses.
Fixes: #15178
We generally return > 1 if any of the actions we are doing is instantly
complete and == 0 when we started doing it asynchronously (by forking
off homework), in our functions that execute operations on homes.
Fix a mix-up where the test for this was reversed in
home_dispatch_release() and home_dispatch_lock_all().
Fixes: #15684
This variable is read by the module and can be used instead of the
suspend= PAM module parameter.
It is also set for the session itself to make debugging easy.
We might pin a home through authentication and a different one through a
session, all from the same PAM context, like sudo does. Hence also store
the referencing fd keyed by the user name.
Since acquiring user records involves plenty of IPC we try to cache user
records in the PAM context between our various hooks. Previously we'd
just cache whatever we acquired, and use it from the on, forever until
the context is destroyed.
This is problematic however, since some programs (notably sudo) use the
same PAM context for multiple different operations. Specifically, sudo
first authenticates the originating user before creating a session for
the destination user, all with the same PAM context. Thankfully, there
was a safety check for this case in place that re-validated that the
cached user record actually matched our current idea of the user to
operate on, but this just meant the hook would fail entirely.
Let's rework this: let's key the cache by the user name, so that we do
not confused by the changing of the user name during the context's
lifecycle and always, strictly use the cached user record of the user we
operate on.
Essentially this just means we now include the user name in the PAM data
field.
Secondly, this gets rid of the extra PAM data field that indicates
whether a user record is from homed or something else. To simplify
things we instead just cache the user record twice: once for consumption
by pam_systemd_home (which only wants homed records) and once shared by
pam_systemd and pam_systemd_home (and whoever else wants it). The cache
entries simply have different field names.
These arguments contain UserRecord structures serialized to JSON,
however only the "secret" part of it, not a whole user record. We do
this since the secret part is conceptually part of the user record and
in some contexts we need a user record in full with both secret and
non-secret part, and in others just the secret and in other just the
non-secret part, but we want to keep this in memory in the same logic.
Hence, let's rename the arguments where we expect a user record
consisting only of the secret part to "secret".
Previously pam_systemd_home.so was relying on `PAM_PROMPT_ECHO_OFF` to
display error messages to the user and also display the next prompt.
`PAM_PROMPT_ECHO_OFF` was never meant as a way to convey information to
the user, and following the example set in pam_unix.so you can see that
it's meant to _only_ display the prompt. Details about why the
authentication failed should be done in a `PAM_ERROR_MSG` before
displaying a short prompt as per usual using `PAM_PROMPT_ECHO_OFF`.
Let's make the logic a bit smarter: if we detect that /home is
encrypted, let's avoid double encryption and prefer plain
directory/subvolumes instead of our regular luks images.
Also, allow configuration go storage/file system via an env var passed
to homework. In a later commit, let's then change homed to initialize
that env var from a config file setting, when invoking homework.
Make use of the new user_record_build_image_path() helper the previous
commit added to share some code.
Also, let's make sure we update all parsed-out fields with the new data
from the binding, so that the parsed-out fields are definitely
up-to-date.
Let's make debugging a bit easier: when invoking homed from the build
tree it's now possible to make sure homed invokes the build tree's
homework binary by setting an env var.
We always need to make them unions with a "struct cmsghdr" in them, so
that things properly aligned. Otherwise we might end up at an unaligned
address and the counting goes all wrong, possibly making the kernel
refuse our buffers.
Also, let's make sure we initialize the control buffers to zero when
sending, but leave them uninitialized when reading.
Both the alignment and the initialization thing is mentioned in the
cmsg(3) man page.
Apparently unpriv clients expect to be able to auth via PAM. Kinda
sucks. But it is what it is. Hence open this up.
This shouldn't be too bad in effect since clients after all need to
provide security creds for unlocking the home dir, in order to misuse
this.
Fixes: #15072
Let's be extra careful whenever we return from recvmsg() and see
MSG_CTRUNC set. This generally means we ran into a programming error, as
we didn't size the control buffer large enough. It's an error condition
we should at least log about, or propagate up. Hence do that.
This is particularly important when receiving fds, since for those the
control data can be of any size. In particular on stream sockets that's
nasty, because if we miss an fd because of control data truncation we
cannot recover, we might not even realize that we are one off.
(Also, when failing early, if there's any chance the socket might be
AF_UNIX let's close all received fds, all the time. We got this right
most of the time, but there were a few cases missing. God, UNIX is hard
to use)