Commits
Allowing the initial_session to specify a PAM service gives the user
additional control over autologin behavior. For example, they can
leverage a PAM session rule to set XDG_SESSION_TYPE before the session
is registered in systemd-logind, ensuring type-dependent details (e.g.
idle state) will be handled correctly.
Consider a system where the desired behavior is:
- initial_session launches an X11 session
- default_session runs tuigreet, from which the user can:
- select an X11 session
- select a Wayland session
- run an arbitrary command, e.g. /bin/sh
In the default_session, if the user selects one of their predefined
sessions, tuigreet sets XDG_SESSION_TYPE appropriately via the env field
of its start_session message). If the user chooses to run an arbitrary
command instead, tuigreet leaves XDG_SESSION_TYPE unspecified, allowing
it to default to "tty".
The initial_session needs a way to set XDG_SESSION_TYPE without
interferring with the default_session behavior. Using a different PAM
service allows it to do that.
The resulting configuration would have an /etc/greetd/config.toml like:
[default_session]
command = "/path/to/tuigreet --sessions /path/to/wayland-sessions --xsessions /path/to/xsessions"
user = "greeter"
[initial_session]
command = "startx"
user = "john"
service = "greetd-autologin"
[terminal]
vt = 1
and a /path/to/greetd-autologin-environment containing:
XDG_SESSION_TYPE DEFAULT="x11"
and an /etc/pam.d/greetd-autologin containing:
auth include greetd
account include greetd
password include greetd
session optional pam_env.so conffile=/path/to/greetd-autologin-environment readenv=0
session include greetd
and an /etc/pam.d/greetd containing:
auth substack login
account include login
password substack login
session include login
and an /etc/pam.d/login containing (among other things):
...
session required pam_env.so conffile=/etc/pam/environment readenv=0
session required pam_unix.so
session required pam_loginuid.so
session optional pam_systemd.so
To start each session worker clean, without any odd Tokio machinery
hanging around in the background, waiting for a weak moment to strike,
we exec session workers to get a fresh, worker-dedicated process.
To obtain a path to exec we called std::env::current_exe, which is a
convenience wrapper provided by the Rust standard library. However, this
ultimately just calls readlink on /proc/self/exe, and this has the
important caveat of not being valid after the original process file is
unlinked.
As we are relying on a Linux-esque /proc, we can rely on a convenient
Linux behavior: /proc/self/exe may not read as a valid link, but it
remains a valid file containing the original process image. As such, we
can simply exec it directly without trying to figure out the path name.
This does mean that we stray further from portability, as e.g., FreeBSD
would need a different strategy. However, we don't have any working
FreeBSD port that I know of right now, so let's just leave a comment and
solve that when we need to.
These were pointed out by clippy. The safer version reduces the chances
of accidentally introducing undefined behaviour during future refactors.
According to https://gitlab.com/mobian1/phog development of phog has
been stopped and phrog should be used instead
Remove redundant lifetimes that are automatically inferred by the
compiler.
While dealing with the large number of casts needed in the PAM ffi code,
the return value of calloc was accidentally cast to a u8 for the error
check, meaning it erroneously thought calloc had failed if the least
significant byte was 0 - which it often wasn't, meaning that users did
not discover the issue.
Avoid casting and just use pointer::is_null.
Even though we are operating under mlock, we might still end up on disk
if the user hibernates. Scramble the user responses in the most obvious
places.
When the session changes to the ready state, the worker can no longer
accept any auth message responses. Send an error to the greeter so it
knows that it violated protocol.
Some X11 start scripts rely on this variable to apss the current VT to
Xorg.
The support for the old config format was meant to ease transition and
has now served its purpose.
This is just an old legacy feature, no need to carry it around anymore.
Users need to ensure that there is a service file for greetd, and if
they are free to copy the one intended for login(1).
We do some presence checks before using certain PAM service files. Check
/usr/lib/pam.d in addition to /etc/pam.d.
Allowing the initial_session to specify a PAM service gives the user
additional control over autologin behavior. For example, they can
leverage a PAM session rule to set XDG_SESSION_TYPE before the session
is registered in systemd-logind, ensuring type-dependent details (e.g.
idle state) will be handled correctly.
Consider a system where the desired behavior is:
- initial_session launches an X11 session
- default_session runs tuigreet, from which the user can:
- select an X11 session
- select a Wayland session
- run an arbitrary command, e.g. /bin/sh
In the default_session, if the user selects one of their predefined
sessions, tuigreet sets XDG_SESSION_TYPE appropriately via the env field
of its start_session message). If the user chooses to run an arbitrary
command instead, tuigreet leaves XDG_SESSION_TYPE unspecified, allowing
it to default to "tty".
The initial_session needs a way to set XDG_SESSION_TYPE without
interferring with the default_session behavior. Using a different PAM
service allows it to do that.
The resulting configuration would have an /etc/greetd/config.toml like:
[default_session]
command = "/path/to/tuigreet --sessions /path/to/wayland-sessions --xsessions /path/to/xsessions"
user = "greeter"
[initial_session]
command = "startx"
user = "john"
service = "greetd-autologin"
[terminal]
vt = 1
and a /path/to/greetd-autologin-environment containing:
XDG_SESSION_TYPE DEFAULT="x11"
and an /etc/pam.d/greetd-autologin containing:
auth include greetd
account include greetd
password include greetd
session optional pam_env.so conffile=/path/to/greetd-autologin-environment readenv=0
session include greetd
and an /etc/pam.d/greetd containing:
auth substack login
account include login
password substack login
session include login
and an /etc/pam.d/login containing (among other things):
...
session required pam_env.so conffile=/etc/pam/environment readenv=0
session required pam_unix.so
session required pam_loginuid.so
session optional pam_systemd.so
To start each session worker clean, without any odd Tokio machinery
hanging around in the background, waiting for a weak moment to strike,
we exec session workers to get a fresh, worker-dedicated process.
To obtain a path to exec we called std::env::current_exe, which is a
convenience wrapper provided by the Rust standard library. However, this
ultimately just calls readlink on /proc/self/exe, and this has the
important caveat of not being valid after the original process file is
unlinked.
As we are relying on a Linux-esque /proc, we can rely on a convenient
Linux behavior: /proc/self/exe may not read as a valid link, but it
remains a valid file containing the original process image. As such, we
can simply exec it directly without trying to figure out the path name.
This does mean that we stray further from portability, as e.g., FreeBSD
would need a different strategy. However, we don't have any working
FreeBSD port that I know of right now, so let's just leave a comment and
solve that when we need to.
While dealing with the large number of casts needed in the PAM ffi code,
the return value of calloc was accidentally cast to a u8 for the error
check, meaning it erroneously thought calloc had failed if the least
significant byte was 0 - which it often wasn't, meaning that users did
not discover the issue.
Avoid casting and just use pointer::is_null.