5.9 KiB
latchd
Want a TUI-based login manager because you are tired of GDM or Plasma Login? Latchd gives you a small, keyboard-first login screen on a Linux virtual terminal. It uses PAM for authentication and can start a TTY shell, an X11 desktop, or a Wayland desktop.
Latchd is written in Rust. The old Go prototype is kept in legacy/go/ for reference and is not built or shipped.
What it does
- Finds normal login accounts through NSS.
- Shows password, account-expiry, locked-account, and faillock status without replacing PAM's decision.
- Lets you switch users and sessions without leaving the login screen.
- Finds X11 and Wayland desktop entries and can include a TTY shell.
- Starts sessions with a cleared, explicit environment and drops privileges before running the user process.
- Records user sessions with UTMPX when the platform provides it.
- Provides a Ratatui TUI with filtering, keyboard help, refresh, notifications, wallpaper, and reduced-motion support.
- Runs safely in preview mode for UI work and configuration checks.
The real login handoff still needs a Linux system with PAM, a virtual terminal, and the display/session services you want to use. The Docker tests cover builds, unit tests, rendering, configuration, and capability probes; they do not pretend to be a real VT or systemd-logind session.
Build
On Debian or Ubuntu, install the build dependencies first:
sudo apt-get install build-essential pkg-config libpam0g-dev libpam-modules
Then run:
make check
make docker-test
make integration-test
make build writes the optimized binary to build/latchd. make package creates a deterministic archive and SHA-256 file in dist/.
Try the UI
Preview mode does not call PAM, start a session, or run power actions:
make run-preview
# or
./build/latchd --preview --no-log
Use LATCHD_ASCII=1 for terminals without reliable Unicode support, NO_COLOR=1 for monochrome output, and LATCHD_HIGH_CONTRAST=1 for a stronger focus palette.
Install on a test machine
Do this on a disposable machine first. Keep another login path available while changing a display manager.
sudo make install
sudo systemctl enable latchd.service
This installs:
/usr/bin/latchd/etc/latchd/config.toml/etc/pam.d/latchd/usr/lib/systemd/system/latchd.service
The default service owns /dev/tty2. Change the tty setting and the unit's TTYPath together when using another virtual terminal.
Configuration
The complete example is in extra/config.toml. Important sections are:
[accounts]controls NSS discovery, the faillock helper, faillock policy, and/etc/shadowaccount-age checks.[x11]and[wayland]select desktop-entry and administrator script directories.[environment_switcher]controls session choices and the optional TTY shell.[visual]controls wallpaper size, animation, notifications, and reduced motion.[power_controls]contains absolute program paths and argv arrays. Commands are never passed through a shell.
Configuration files used by a real root service must be root-owned and not writable by group or other users. Use a variables file for deployment-specific values instead of putting secrets in command arguments.
Controls
| Key | Action |
|---|---|
| Tab / Shift-Tab | Move focus |
| Up / Down | Move focus or move in a filtered list |
| Left / Right | Change the selected session |
/ |
Filter sessions or discovered accounts |
| Ctrl-R | Refresh account and session discovery |
| Ctrl-N / Ctrl-P | Select the next or previous account |
| Ctrl-B | Toggle wallpaper and ambient effects |
| Ctrl-M | Toggle reduced motion |
| Enter | Authenticate from the password field |
| Esc | Clear the password or close a popup |
? |
Show keyboard help |
| Ctrl-C | Restore the terminal and quit |
| F1–F12 | Confirm a configured power action |
The filter is smart-case: lowercase searches ignore case; a search containing uppercase characters is case-sensitive. The account-age and faillock messages are advisory. PAM remains the only authorization decision.
Testing a deployment
The ordinary tests do not need a privileged container:
make check
make audit
make docker-test
make integration-test
make system-e2e
make system-e2e reports real host capabilities as PASS, SKIP, or FAIL. It does not call an account password or claim that a pseudo-terminal is a virtual terminal. make system-e2e-strict is for a prepared disposable VM with a test PAM policy, a real VT, systemd-logind, and the X11 or Wayland stack under test. See docs/e2e-testing.md.
Security notes
- PAM handles stay on one worker thread.
- Password buffers are zeroized and never placed in argv, logs, or the TUI.
- Session environments are rebuilt from an allowlist.
- Desktop files, scripts, binaries, homes, logs, and configuration sources are checked before use.
- Xauthority files and session logs use private permissions and cleanup guards.
- Power actions require confirmation and are disabled in preview mode.
- Account status and faillock output never bypass PAM or provide an administrator unlock shortcut.
Project layout
crates/latchd-core/ configuration, account discovery, sessions, UTMPX
crates/latchd-auth/ PAM FFI and the authentication worker
crates/latchd-tui/ Ratatui state, rendering, filtering, and effects
rust/main.rs command-line entry point and service orchestration
extra/ example configuration, PAM policy, and systemd unit
scripts/ Docker and CLI/system capability tests
legacy/go/ non-production Go reference
Releases
GitLab CI runs formatting, tests, Clippy, rustdoc, RustSec auditing, CLI integration tests, capability probes, and the Docker suite. SemVer tags produce a reproducible Linux archive with checksums. Live VT, PAM-policy, X11, Wayland, and logind validation belongs in the isolated VM gate described above.
License
Apache-2.0. See LICENSE.