2026-07-18 18:16:06 +05:30

latchd

Want a TUI-based login manager because you are tired of GDM or Plasma Login? Latchd puts a small, keyboard-driven 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 remains in legacy/go/ for reference. It is not part of the release build.

Latchd login screen

The image above is the preview screen. It was captured from the Docker test image. See docs/ui.md for the keyboard reference and the second screenshot.

Features

  • Discovers normal login accounts through NSS.
  • Shows account expiry, locked-account, and faillock status before login.
  • Lets PAM handle authentication and password changes.
  • Switches between users and sessions from the same screen.
  • Finds X11 and Wayland desktop entries from configured directories.
  • Can offer a TTY shell as a session choice.
  • Starts the selected session with a restricted environment and the correct user ID.
  • Passes the selected session, seat, and virtual terminal to PAM and logind.
  • Imports approved values from PAM into the session environment.
  • Writes UTMPX records when the platform supports them.
  • Provides filtering, keyboard help, refresh, notifications, wallpaper, and reduced-motion controls.
  • Has a preview mode for UI work and configuration checks.

The service needs Linux PAM and a virtual terminal. X11 and Wayland sessions also need their own display server, compositor, and desktop files. Docker covers the parts that do not require those host services. The remaining checks must run on a prepared machine or VM.

Requirements

Builds use Rust 1.88 and the system PAM development files. On Debian or Ubuntu:

sudo apt-get install build-essential pkg-config libpam0g-dev libpam-modules

The repository includes the required rustfmt and clippy components in rust-toolchain.toml.

Build and run

Run the local verification gate and build the release binary:

make check
make build

The binary is written to build/latchd. To open the non-authenticating preview:

make run-preview
# or
./build/latchd --preview --no-log

Preview mode does not contact PAM, start a user session, or run power actions. It is safe to use while changing the layout or configuration.

For terminals with limited character support, set LATCHD_ASCII=1. Set NO_COLOR=1 for plain output. Set LATCHD_HIGH_CONTRAST=1 for a stronger focus colour.

Configuration

The example file is extra/config.toml. Latchd uses separate paths for a system service and a local preview:

  • A root service reads /etc/latchd/config.toml.
  • Preview mode first checks $XDG_CONFIG_HOME/latchd/config.toml.
  • If XDG_CONFIG_HOME is not set, preview mode checks ~/.config/latchd/config.toml.
  • --config PATH selects a file explicitly and takes precedence over the defaults.

Create the user file from the example:

make install-user
./build/latchd --preview --no-log

make install-user creates ~/.config/latchd/ with mode 700 and creates config.toml with mode 600. It does not replace an existing file. Set USER_CONFIG_HOME=/path or XDG_CONFIG_HOME=/path when the file must be stored elsewhere.

The main sections in the example are:

  • [accounts] for NSS discovery, faillock, and account-age checks.
  • [x11] and [wayland] for desktop-entry and administrator script directories.
  • [environment_switcher] for session choices and the last-session preference file.
  • [visual] for wallpaper, animation, notification, and reduced-motion settings.
  • [power_controls] for confirmed power commands. Latchd starts these programs directly; it does not use a shell.

Keep the system file owned by root and unwritable by group or other users. Do not put passwords or other secrets in command-line arguments.

Install on a test machine

Use a disposable machine first. Keep another login path available while changing the 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 supplied service uses /dev/tty2. If you choose another VT, change both the tty value in the config and TTYPath in the systemd unit. Stop or disable the existing display manager before enabling latchd on the same terminal.

Keyboard 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 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 or submit a PAM password change
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

Lowercase filters ignore case. A filter with an uppercase letter is case-sensitive. The status line can show account and faillock information before login.

Testing

Run the local checks with these commands:

make check
make integration-test
make docker-test
make system-e2e

Run make audit after you install cargo-audit. Run make pam-fixture-test as root. The PAM fixture command creates temporary policies and removes them when it exits.

make system-e2e checks the PAM library, faillock, virtual terminal, X11, Wayland, and systemd-logind on the current host. It prints PASS, SKIP, or FAIL. A pseudo-terminal does not provide a virtual terminal. The check does not install a PAM policy or start systemd-logind.

Run the strict check in a disposable VM with a test PAM policy, a real VT, systemd-logind, and the X11 or Wayland stack you want to test:

make system-e2e-strict

See docs/e2e-testing.md for the test limits and VM setup.

Security notes

  • PAM handles stay on one worker thread.
  • Password buffers are zeroized. Passwords are not written to argv, logs, or the TUI.
  • Audit records contain the account and a stable result code. They do not contain PAM's free-form error text or password data.
  • Session environments are rebuilt from an allowlist.
  • Latchd checks desktop files, scripts, binaries, home directories, logs, and configuration files before use.
  • Xauthority files and session logs use private permissions and cleanup guards.
  • Power commands need confirmation and are disabled in preview mode.
  • Account and faillock checks do not unlock accounts or bypass PAM.

Project layout

crates/latchd-core/  configuration, account discovery, sessions, and UTMPX
crates/latchd-auth/  PAM FFI, password changes, 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, CLI, PAM, and system capability tests
legacy/go/           non-production Go reference

Releases

GitLab CI runs formatting, tests, Clippy, rustdoc, RustSec checks, CLI tests, capability checks, and the Docker suite. A SemVer tag runs the package job and publishes a Linux archive with its SHA-256 file. The strict VT, PAM, X11, Wayland, and logind checks are separate because CI containers do not provide those host services.

Create a local package with:

make package

License

Apache-2.0. See LICENSE.

Description
No description provided
Readme Apache-2.0 380 KiB
Languages
Rust 72.9%
Go 20.1%
Shell 3.5%
Makefile 3.4%