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:
| Platform | Display-server | Modul | Hvordan |
|---|---|---|---|
| Linux | Wayland | ahfail-module.so | Indlæses direkte af gtklock via dens modul-API |
| Linux | X11 | libahfail_pam.so + ahfail-display | PAM-hook spawner display-binæren efter hver fejlet auth |
| macOS | .. | libahfail_pam.so + ahfail-display | Samme PAM-tilgang, hooker ind i screensaver-stakken |
På 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)
På 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.