11. juni 2026

Ah ah ah, you didn't say the magic word.. en skærmlås-prank i Rust

Et af mine mere fjollede sideprojekter: ah-fail. Taster du dit kodeord forkert på låseskærmen, popper der en loopende animation op af mit eget ansigt photoshoppet ind på Dennis Nedrys krop fra Jurassic Park, mens “ah ah ah, you didn’t say the magic word” spiller i fuld lydstyrke. Hvert forkert gæt tilføjer en ny sprite på en tilfældig position på skærmen. Lydstyrken tvinges til 100 % på første fejl og sættes tilbage, når du endelig låser op.

Det er en prank. Men vejen dertil lærte mig en del om, hvor følsomt authentication-laget på et system egentlig er.

Hvorfor jeg skrottede ANSI C

Jeg startede projektet i ANSI C. Det giver god mening på papiret: det her hooker ind i PAM, og PAM er skrevet i C. Men der er et problem.. PAM sidder direkte i authentication-kritiske sti. Min kode bliver indlæst ind i selve den proces, der afgør, om du må komme ind på maskinen.

Og med manuel hukommelsesstyring blev det hurtigt for risikabelt. Jeg jagtede use-after-free og små lækager i en kontekst, hvor en enkelt fejl i værste fald låser dig ude af dit eget system eller svækker login. En segfault i et lille hobby-PAM-modul er ikke bare en crash.. det er en crash i din låseskærm.

Så jeg skrev det hele om til Rust. Hukommelsessikkerheden er ikke et nice-to-have her, den er hele pointen: jeg vil have compileren til at fange den slags fejl, før de nogensinde rammer en authentication-proces. Resten af projektet blev til en Cargo workspace, bygget med Meson, og koden, der rører PAM, blev holdt så minimal som overhovedet muligt.

Sådan hænger det sammen

Integrationen afhænger af din display-server, og det er her, det bliver lidt sjovt:

PlatformDisplay-serverModulHvordan
LinuxWaylandahfail-module.soIndlæses direkte af gtklock via dens modul-API
LinuxX11libahfail_pam.so + ahfail-displayPAM-hook spawner display-binæren efter hver fejlet auth
macOS..libahfail_pam.so + ahfail-displaySamme PAM-tilgang, hooker ind i screensaver-stakken

Wayland kan jeg bruge gtklocks interne vindues-API og tegne sprites direkte oven på låseskærmen. På X11 og macOS findes der ikke sådan et plugin-API, så her gør jeg det via et PAM-modul: det registrerer et cleanup-callback, der fyrer ved hver fejlet authentication, og double-forker en selvstændig display-binær (ahfail-display), som kører helt uafhængigt af PAM-stakken. Det vigtigste: PAM-modulet rører aldrig dine credentials. Det reagerer kun på, at et forsøg fejlede.

Al den fælles logik (animation, lyd, deadzone, volumen) ligger i én delt crate, ahfail-ui, så gtklock-modulet og display-binæren deler præcis samme adfærd.

Installation: Wayland (gtklock)

På Arch henter du afhængighederne og bygger med Meson:

sudo pacman -S meson ninja rust gtk3 gstreamer gst-plugins-base \
  gst-plugins-good gst-plugins-bad gtklock
meson setup builddir --prefix=/usr
meson compile -C builddir
sudo meson install -C builddir

--prefix=/usr er vigtig.. uden den defaulter Meson til /usr/local, og så matcher den indbyggede sti i binæren ikke der, hvor filerne faktisk lander. Derefter starter du bare gtklock med modulet:

gtklock -m /usr/lib/gtklock/ahfail-module.so

Hold dit password-felt frit for sprites med en deadzone:

gtklock -m /usr/lib/gtklock/ahfail-module.so -- --deadzone=860,440,200,200

Installation: X11 (i3lock, xscreensaver, ..)

PAM-modulet virker med enhver X11-locker, der authenticator via PAM. Du tilføjer en linje til lockerens PAM-service-fil (fx /etc/pam.d/i3lock eller /etc/pam.d/xscreensaver).

Her er den fælde der kostede mig mest tid: ahfail-linjen skal stå før auth include system-auth. Står den efter, så betyder PAM’s interne flow-kontrol inde i system-auth (pam_faillock med [default=die]), at mit modul aldrig bliver nået ved et fejlet forsøg.. det bliver kun kaldt ved succes, hvilket er det stik modsatte af, hvad jeg vil.

Stien til modulet afhænger af distro:

# Arch / standard (--prefix=/usr)
#%PAM-1.0
auth optional /usr/lib/ahfail/libahfail_pam.so
auth include system-auth
# Debian / Ubuntu (multiarch)
#%PAM-1.0
auth optional /usr/lib/x86_64-linux-gnu/ahfail/libahfail_pam.so
auth include system-auth
# Fedora / RHEL (multilib)
#%PAM-1.0
auth optional /usr/lib64/ahfail/libahfail_pam.so
auth include system-auth

Den fulde sti er nødvendig.. $(libdir)/ahfail ligger ikke i PAM’s standard-søgesti.

Installation: macOS

Den nemme vej er Homebrew:

brew tap agw/ahfail https://gitea.weircon.dk/agw/homebrew-ahfail
brew install ahfail

Bagefter printer Homebrew den ene PAM-linje, du skal tilføje til /etc/pam.d/screensaverui (macOS 13 og nyere) eller /etc/pam.d/screensaver (macOS 12 og ældre). Den manuelle ét-linjes-rettelse er det eneste trin tilbage, og opgradering er bare brew upgrade ahfail.

Vil du hellere bygge fra kilde, klarer install-scriptet dependencies, build og PAM-konfiguration på én gang:

git clone https://gitea.weircon.dk/agw/gtk-ahfail.git
cd gtk-ahfail
bash scripts/install-macos.sh

Et lille Apple Silicon-gotcha jeg ramte: Homebrew bruger /opt/homebrew som prefix på ARM, men /usr/local på Intel. Den indbyggede default-sti skal sættes ved build-tid (-Dlibdir), ellers peger PAM-modulet på den forkerte placering på den ene af de to.

En ærlig advarsel

Det her hooker ind i PAM og/eller din lockers plugin-API. PAM sidder i authentication-kritiske sti.. en fejl i modulet kan i værste fald låse dig ude eller svække dit login. Jeg giver ingen garantier. Installerer du det, ændrer du en sikkerhedskritisk komponent i dit system og påtager dig selv ansvaret. Det er fjollet i sin natur, men det skal behandles seriøst.

Hvad der ikke virker (endnu)

swaylock og hyprlock fyrer PAM-modulet fint ved fejlede forsøg, men animationen bliver ikke vist. Waylands session-lock-protokol (ext-session-lock-v1) tillader kun lockeren selv at tegne, så compositoren undertrykker min sprite, og kun lyden spiller. Fuld support kræver, at swaylock og hyprlock eksponerer et plugin-API ligesom gtklock. Indtil da er det Wayland via gtklock, eller X11.

Koden

Hele projektet ligger offentligt på gitea.weircon.dk/agw/gtk-ahfail. Spriten er mit ansigt på Nedrys krop, men du kan nemt bytte den ud med dit eget PNG-sekvens i assets/ og bygge om. God fornøjelse.. og husk din deadzone.

Kommentarer