# 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. - Runs PAM password changes for accounts that require a new password before login. - Lets you switch users and sessions without leaving the login screen. - Remembers each account's last successful session choice in a root-owned state file. - 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. - Registers the selected desktop, session type, seat, and VT with PAM/logind, then imports only approved PAM runtime values into the user session. - 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: ```sh sudo apt-get install build-essential pkg-config libpam0g-dev libpam-modules ``` Then run: ```sh 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: ```sh 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. ```sh 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`](extra/config.toml). Important sections are: - `[accounts]` controls NSS discovery, the faillock helper, faillock policy, and `/etc/shadow` account-age checks. - `[x11]` and `[wayland]` select desktop-entry and administrator script directories. - `[environment_switcher]` controls session choices, the optional TTY shell, and the owner-checked last-session preference file. - `[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, or submit a PAM password change when requested | | 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: ```sh make check make audit make docker-test make integration-test make pam-fixture-test # runs when root is available; otherwise reports SKIP 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`](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. - Security audit events contain only the account name and stable outcome/reason fields; PAM's free-form error text and password material are not logged. - 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 ```text crates/latchd-core/ configuration, account discovery, sessions, 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 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`](LICENSE).