9.2 KiB
Changelog
Unreleased
- Fixed Wayland compositors launched through user services, including Niri, by
providing the selected session type, desktop, seat, and VT to PAM before
pam_open_session. - Session children now receive allowlisted runtime values produced by PAM,
including the real logind session ID, runtime directory, and user D-Bus
address. Latchd no longer fabricates
XDG_SESSION_ID=latchd. - Extended the disposable PAM fixture to verify both sides of the handoff: selected session metadata entering PAM and PAM-generated values reaching the session child.
0.5.0 — PAM password policy flow
- Added PAM password-change handling for accounts that return
PAM_NEW_AUTHTOK_REQDorPAM_AUTHTOK_EXPIREDduring login. - Added an explicit TUI new-password state. PAM still enforces password history, strength, and token policy; the login screen never implements its own password rules.
- Added zeroizing old/new password buffers and conversation tests for the current-password/new-password prompt sequence.
- Added redacted structured audit events for authentication, password changes, and session handoff. Raw PAM messages and password material are excluded.
- Added TUI, core, and preference tests; the workspace now contains 37 Rust unit tests.
- Added bounded, atomic last-session preferences per account with owner-only file permissions and a safe fallback when the state file is unavailable.
- Added disposable PAM deny-policy fault-injection tests. Docker runs them as root; ordinary host runs skip them without touching the host PAM policy.
0.4.0 — Advanced login workflow
- Added account policy inspection for locked passwords, password expiry, account expiry, inactivity, and missing shadow data without exposing hashes.
- Added active UTMPX session discovery and systemd-logind capability detection with an explicit UTMPX fallback.
- Improved faillock parsing for legacy, username-prefixed, and timestamped helper output. PAM remains authoritative for every login decision.
- Added smart-case filtering for users and sessions, non-blocking Ctrl-R discovery refresh, contextual footer hints, high-contrast mode, and policy notices in the TUI.
- Added bounded local authentication backoff after repeated failures and reset it when switching accounts.
- Added CLI integration tests and host capability probes. Docker now runs the release binary through the safe CLI and capability suites.
- Added documented strict VM validation for PAM policy, VT, X11, Wayland, and systemd-logind; missing capabilities are reported as skips in ordinary CI.
- Bumped the workspace release version to 0.4.0.
0.3.0 — Rust workspace release preparation
- Rust is the supported login manager; the Go/cgo prototype is quarantined at
legacy/go/and excluded from normal builds and release archives. - Added workspace crates for PAM authentication, session/config/account management, and the TUI, including account switching and advisory faillock.
- Added optional terminal-cell wallpapers, cellular automata effects, and accessible motion/background controls.
- Added GitLab CI verification, version-checked tag releases, optimized single-version Cargo builds, deterministic installation archives, SHA-256 checksums, and embedded build metadata.
- Live VT, logind, PAM-policy, X11, and Wayland validation remains a deployment requirement on an isolated VM or target host.
Legacy Go history (not the Rust release)
0.1.0 — Unreleased
first public release
What's In
- tui login screen with username/password fields, session switcher, and status messages
- supports x11, wayland, and tty sessions
- pam authentication via cgo (thread-locked for safety)
- faillock integration — detects lockouts, shows remaining attempts, admin bypass via ctrl+u
- conway's game of life background rendered at 30 fps with unicode half-block characters
- spring animation on switcher transitions
- shake animation on failed login
- caps lock indicator via ioctl
- configurable power controls (shutdown/reboot on f1/f2 by default)
- toml configuration with
$VARIABLEsubstitution - preview mode (
--preview) to test the login screen without leaving your session - utmpx user accounting (glibc only)
- x11 session setup — xauthority cookies, sigusr1 handshake, server timeout
- privilege dropping for child processes
- log piping with 64 mb cap
Recent Fixes
-
DesktopNames parsing —
.desktopfiles now parse theDesktopNamesfield. the first semicolon-delimited entry becomesXDG_SESSION_DESKTOP, and the full list with:separators becomesXDG_CURRENT_DESKTOP. fixes GNOME/KDE sessions not getting proper environment variables -
utmpx accounting wired —
AddUtmpxandCloseare now called fromspawnSessionso user logins appear inwho/w/last -
fixed hardcoded shell —
Credentials.Shellnow reads from/etc/passwdinstead of always returning/bin/sh. removes duplicateuserShelllogic in exec.go -
automata background wired —
Automata.Frame()is now rendered inView()as the base layer with the login form card overlaid using ANSI cursor positioning. the form has a dark card background for readability -
clock widget — added a datetime display (
Mon Jan 02 15:04:05) to the top bar, updated every tick -
session specifier label — the environment switcher now shows the session type (
x11,wayland) above the session name, like ly's specifier -
form card background — login content is rendered inside a padded card with a dark background so it reads cleanly over the animated automata
-
utmpx time field portability — replaced hardcoded
C.__uint32_t/C.__int32_tcasts with a C helper function (auth/utmpx_time.h) that lets the compiler handle type conversion. fixes build failure on systems whereut_tvusesstruct timevalinstead of the 32/64 compat struct -
cgo pointer safety for pam — replaced
unsafe.Pointer(&h)(Go stack pointer passed to C) withstoreHandle/loadHandlehelpers that keep thecgo.Handlein C-heap memory. fixescgo argument has Go pointer to unpinned Go pointerpanic on Go 1.22+ -
pam conversation callback — fixed
unsafe.Sliceusing&r(pointer-to-pointer) as the backing array instead ofr(the calloc'd response array), which wrote password bytes into random stack memory. also now only responds toPAM_PROMPT_ECHO_OFF/PAM_PROMPT_ECHO_ONmessages — info and error messages get nil. fixespam_unix: auth could not identify password -
cgo handle lifecycle — moved
cgo.Handleand its C-heap backing fromValidate(where they weredefer-freed on return) into theCredentialsstruct so they stay alive throughOpenSessionand untilCloseSession. fixesmisuse of an invalid Handlepanic -
session spawning — replaced the broken
ForkExec(which relaunched the same binary with made-up flags) with a directsession.Spawncall that drops privileges and runs the desktop in-process. fixesflag provided but not defined: -user -
renamed extra/ files —
lemurs.pam→latchd.pam,lemurs.service→latchd.service -
readme credits — added a credits section acknowledging lemurs for the
extra/directory structure and session scanning approach -
makefile
enableandupdatetargets —make enablestops any running DM, disables the aliased display-manager, and enables latchd.make updateruns uninstall → git pull → reinstall in one command -
missing
extra/directory — addedextra/config.toml,extra/xsetup.sh,extra/lemurs.pam, andextra/lemurs.servicesomake installcan find them -
makefile
depstarget — addedmake depsto automatically installlibpam0g-devandbuild-essential, and verify go is present -
readme overhaul — rewrote for clarity: added "what problem does this solve", "how it works", known issues, simpler install instructions, and proper dependency listing
-
view cleanup — removed the non-functional automata background overlay from
View()(theFrame()was never called, and the black-space placeholder causedEEEEgarbage characters on some terminals). also removed a hardcoded 80-char width on the top bar so it adapts to the terminal -
session environment setup —
spawnSessionnow callsSetBasicVariables,SetDisplay,SetSessionParams,SetSeatVars,SetSessionVars, andSetXDGCommonPathsbefore spawning the desktop. fixessetupXfailing immediately withmissing DISPLAY/XDG_VTNR/HOME env varsbecause none were set -
pam session error made non-fatal —
pam_open_sessionfailure (e.g.pam_systemdrejecting the DM process as session leader) is now logged as a warning instead of blocking the entire session spawn. also removedsession include loginfromlatchd.pamsince the DM process can't register user sessions with systemd-logind -
global session switching with
,and.— sessions can now be switched from any mode (not just when the switcher is focused). arrows still work when switcher is focused
What's Missing
- no tests
- session leader is the latchd process, not the desktop — pam session tracking via systemd-logind may be imperfect
- not all config options affect the rendering yet
- occasional terminal state corruption on abrupt exit
- automata background visible at screen edges; form card covers the center