Files
pw/content/blog/ah-fail-skaermlaas-rust/index.md
T
Asger Geel WeirsøeandClaude Opus 5.5 e58a11c2b4 feat: flyt sitet fra Astro til Zola
Samme indhold, URL'er og udseende, bygget af en enkelt zola-binær og Tailwind
standalone-CLI uden Node. Kanonisk domæne er asger.weirsoe.dk.

Blogindlæg ligger som page bundles med frontmatter Zola forstår, så de gamle
stempler er ugyldige, indtil scripts/omstempl.py er kørt med PUBLISH_KEY.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-11-01 16:47:08 +01:00

6.9 KiB

title, description, date, taxonomies, draft, extra
title description date taxonomies draft extra
Ah ah ah, you didn't say the magic word.. en skærmlås-prank i Rust Hvorfor jeg droppede ANSI C til fordel for Rust, og hvordan du installerer ah-fail på Wayland, X11 og macOS. 2026-06-11
tags
rust
pam
gtklock
wayland
linux
macos
false
godkendt
v1:c8d80c56e01731b150a66ec9dcdfca911d932ea1721145fb79e3cbf46bc26046

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.