
Linux Desktop Fingerabdruck Anmeldung mit einem Grow R503 Sensor + Arduino + einem Rust fprintd-Ersatz Daemon
Ein aus Einzelteilen zusammengebauter USB-Fingerabdruckleser für Linux-Desktops. Gesamtkosten der Teile unter 15 $. Direkter Ersatz für das ursprüngliche fprintd — PAM, KDE-Einstellungen, GNOME-Einstellungen, fprintd-verify, sudo mit Fingerabdruck, Bildschirmentsperrung mit Fingerabdruck – alles funktioniert.
Ab fw=1.0 / r503d 1.0.0 ist die Arduino↔Host-Verbindung authentifiziert: jeder Befehl und jede Antwort trägt einen SipHash-2-4-MAC, der mit einem über TOFU (Trust on First Use) festgelegten Geheimnis im EEPROM signiert ist. Replay- und Hot-Swap-Angriffe auf die USB-Seriellverbindung werden blockiert. Siehe SPEC.md §13 für das vollständige Design, einschließlich dessen, was das Bedrohungsmodell nicht abdeckt.

wünschte, ich hätte einen 3D-Drucker…``` ┌──────────┐ UART ┌─────────────┐ USB-CDC ┌──────────────────┐ │ Grow │ 57600 8N1│ Arduino │ /dev/r503 │ r503d daemon │ │ R503 │◀─────────▶│ (firmware) │◀──────────▶│ net.reactivated │ │ sensor │ 3.3V TTL │ │ framed, │ .Fprint on D-Bus│ └──────────┘ └─────────────┘ MAC'd └──────────────────┘ │ ▼ PAM, KDE, GNOME, fprintd-verify, …
## Warum
Hardware-USB-Fingerabdruckleser für Linux sind rar, teuer und die
vorhandenen (Validity, Synaptics, etc.) werden durch instabile
libfprint-Treiber reverse-engineered, die bei Hersteller-Firmware-Updates
brechen. Das Protokoll des Grow R503 ist **öffentlich**, die Arduino-Seite
ist eigener Code und die libfprint-Kompatibilitätsschicht ist nur D-Bus.
Sie erhalten außerdem einen Fingerabdruckleser, dessen Quelle Sie
vollständig einsehen können.
## Stückliste
| Bauteil | Hinweise | Ungefähre Kosten |
|------|-------|------|
| Grow R503 kapazitiver Fingerabdrucksensor | Der runde mit dem RGB-Ring | ~$10 |
| Arduino Uno R3 / Nano / Mega / beliebiges ATmega328-Board | Alles, was SoftwareSerial ausführt | $5–$25 |
| 4–6 Jumper-Kabel | Dupont / Steckbrett | trivial |
Das war's. **Kein Pegelwandler, kein Spannungsteiler** — siehe
[`SPEC.md` §3.1](https://github.com/matpb/linux-fingerprint-r503/blob/main/SPEC.md) für den Grund (die RX-Leitung des R503 ist in
der Praxis 5V-tolerant; das Datenblatt lügt).
## Verkabelung```
R503 Arduino (Uno R3 / Nano / etc.)
---- ------------------------------
Red (VCC) 3V3
White (3.3VT) 3V3 (touch-IC supply; shares rail with red)
Black (GND) GND
Yellow (TXD) D2 ── SoftwareSerial RX
Brown (RXD) D3 ── SoftwareSerial TX (direct — no divider!)
Blue (WAKEUP) D4 (optional; not used by firmware yet)
Falls Ihr R503 mit dem JST-SH-Stecker geliefert wird, schneiden Sie ein 6-poliges JST-SH-auf-Dupont-Kabel ab, um die Drähte freizulegen. Braun ist manchmal grün, je nach Verkäufer – prüfen Sie gegen den Draht, der in den RXD-Pin des JST-Steckers geht, nicht die Farbe.
Getestet auf Fedora 44 KDE; sollte auf jeder systemd-basierten Distribution mit fprintd, pam_fprintd und einer aktuellen Rust-Toolchain funktionieren.
Systempakete:
| Distribution | Build | Laufzeit |
|---|---|---|
| Fedora / RHEL | rust cargo arduino-cli tpm2-tss-devel | fprintd pam fprintd-pam tpm2-tss |
| Debian / Ubuntu | rustc cargo arduino-cli libtss2-dev | fprintd libpam-fprintd libtss2-esys-3.0.2-0 |
Die tss-esapi Pakete werden nur benötigt, wenn Sie --pair --seal-tpm (SPEC §13.12) verwenden möchten. Der Daemon baut und läuft ansonsten ohne TPM – tss-esapi ist eine harte Build-Abhängigkeit, aber eine weiche Laufzeitabhängigkeit (der Codepfad wird nur betreten, wenn /var/lib/r503d/key.tpm existiert).
Rust 1.95+, arduino-cli in Ihrem $PATH.
Haben Sie ein TPM2?```bash ls /dev/tpmrm0 && tpm2_pcrread sha256:7 | head -3
Wenn beide erfolgreich sind, kann Ihr Host den versiegelten Schlüsselpfad verwenden. Falls `/dev/tpmrm0` fehlt (ältere Hardware, TPM im BIOS deaktiviert oder eine VM ohne virtuelles TPM), bleiben Sie beim standardmäßigen Klartext-Schlüsselablauf.
## Erstellen & installieren
### 1. Firmware flashen
Öffnen Sie `firmware/r503fp/r503fp.ino` in der Arduino IDE und laden Sie es hoch. Oder mit
`arduino-cli`:```bash
# Uno R3:
arduino-cli compile --fqbn arduino:avr:uno firmware/r503fp/
arduino-cli upload --fqbn arduino:avr:uno --port /dev/ttyACM0 firmware/r503fp/
# Nano (modern Optiboot, including most Elegoo / WAVGAT clones):
arduino-cli compile --fqbn arduino:avr:nano:cpu=atmega328 firmware/r503fp/
arduino-cli upload --fqbn arduino:avr:nano:cpu=atmega328 --port /dev/ttyUSB0 firmware/r503fp/
# Nano with legacy 57600-baud bootloader (older clones):
# replace `cpu=atmega328` with `cpu=atmega328old`
Die Firmware verwendet Adafruit_Fingerprint. Die IDE bietet an, es beim ersten Kompilieren zu installieren.
Wenn arduino-cli upload mit not in sync: resp=0x7e fehlschlägt, ist Ihr Bootloader die andere Variante — tauschen Sie atmega328 ↔ atmega328old und versuchen Sie es erneut. Beide funktionieren; der Unterschied ist nur die Bootloader-Baudrate.
Erfordert Rust 1.95+.```bash cd pcside/daemon cargo build --release
### 3. Installation```bash
sudo bash pcside/daemon/dist/install.sh
Dieses Skript:
target/release/r503d nach /usr/local/bin/r503d/var/lib/r503d/ (Modus 0700 root:root) für den Schlüssel, den Zustand und die Benutzer-Slot-Registrierung/dev/r503 bereitstellt und den Geräteknoten auf root:root 0600 sperrt (nur der Daemon, der als root läuft, benötigt ihn; dies schließt den Standardpfad 0660 root:dialout, sodass kein anderer lokaler Benutzer den Port öffnen kann — Sicherheitsaudit 2026-05-28 / H1). Konsequenz: Nach der Installation benötigt jeder manuelle arduino-cli/serial-monitor-Befehl gegen /dev/r503 sudo./etc/systemd/system/r503d.service)net.reactivated.Fprint/usr/share/polkit-1/actions/net.reactivated.fprint.device.r503d.policy), die vom Aufruferidentitäts-Gate verwendet wirdEs ist idempotent — führen Sie es nach jedem cargo build --release erneut aus, um die neue Binärdatei bereitzustellen.
Ein frisch geflasheter Nano ist ungekoppelt — der Daemon würde mit ihm sprechen, aber die Firmware würde jeden Rahmenbefehl ablehnen. Wählen Sie einen der beiden folgenden Abläufe; beide enden mit einem gekoppelten Nano und einem funktionierenden Daemon. Der TPM-gesiegelte Ablauf wird empfohlen, wenn Ihr Host ein TPM2 besitzt (siehe Voraussetzungen für die schnelle Überprüfung).
Die Opt-in-Datei (/etc/r503d/allow-pair), die in beiden Abläufen verwendet wird, dient dazu, einen Angreifer abzuwehren, der mit seinem eigenen Nano zu Ihrem Schreibtisch eilt — Kopplung ohne root ist unmöglich. r503d --pair löscht den Marker bevor der Schlüssel an den Nano gesendet wird: Wenn der Host zwischen dem Commit auf der Nano-Seite und der Persistenz auf der Host-Seite abstürzt, ist das Gate bereits geschlossen, sodass der nächste Kopplungsversuch Admin-Rechte erfordert, um den Marker erneut zu touchen. Ein vorzeitiger Abbruch (kein Marker oder „bereits gekoppelt“) lässt den Marker für einen erneuten Versuch intakt.
Verwenden Sie dies, wenn Sie kein TPM2-Gerät besitzen oder keinen Schutz vor Offline-Datenträger-Angriffen benötigen.```bash sudo systemctl stop r503d sudo mkdir -p /etc/r503d sudo touch /etc/r503d/allow-pair # opt-in (see SPEC §13.5) sudo r503d --pair # 128-bit key → /var/lib/r503d/key sudo systemctl start r503d
| ... |```bash
sudo r503d --status
# port: /dev/r503
# firmware: fw=1.1 fmt=2
# firmware paired: true
# firmware counter: 42
# host key.tpm: (absent)
# host key: /var/lib/r503d/key
# host key.bak: /var/lib/r503d/key.bak
# tpm device: (absent)
# allow-pair: (absent)
Gleicher Ablauf, plus --seal-tpm. Der generierte Schlüssel wird an PCR7 (Secure Boot-Richtlinie + Schlüssel) gesiegelt und an /var/lib/r503d/key.tpm statt an die Klartext-Datei key geschrieben. Angreifer mit Offline-Datenträgern (dd einer nicht gemounteten Partition, SSD-Tausch in einen feindlichen Host) erhalten nur den Chiffretext.```bash
sudo systemctl stop r503d
sudo mkdir -p /etc/r503d
sudo touch /etc/r503d/allow-pair
sudo r503d --pair --seal-tpm # seals new key to current PCR7
sudo systemctl start r503d
I cannot proceed without the content to translate. Please provide the chunk text.```bash
sudo r503d --status
# port: /dev/r503
# firmware: fw=1.1 fmt=2
# firmware paired: true
# firmware counter: 12
# host key.tpm: /var/lib/r503d/key.tpm
# host key: (missing)
# host key.bak: (missing)
# tpm device: /dev/tpmrm0
# allow-pair: (absent)
Kernel-Updates, initrd-Updates, fwupd UEFI-Firmware-Updates und grub2-Updates ändern nicht PCR7 und erfordern kein erneutes Versiegeln. PCR7 ändert sich nur bei Änderungen der Secure-Boot-Richtlinie, MOK-Eintragungen oder beim Verschieben der Festplatte auf einen anderen Host — an diesem Punkt weigert sich der Daemon zu starten mit TPM_RC_POLICY_FAIL und dist/reseal-tpm.sh erholt sich in etwa 90 Sekunden. Siehe Wiederherstellung: PCR7 geändert.
fprintd-enroll mat
fprintd-verify mat
sudo whoami
Sowohl die KDE-Einstellungen (Plasma 6) als auch die Dialoge für Benutzerkonten-Fingerabdrücke des GNOME Control Centers steuern `r503d` genauso an, wie sie das originale `fprintd` ansteuern.
### Erneutes Pairing / Schlüsselrotation
Wenn Sie einen neuen Schlüssel möchten (Schlüssel kompromittiert, geplanter Hardwaretausch, Paranoia):```bash
sudo systemctl stop r503d
sudo r503d --unpair # framed; wipes Nano EEPROM + host key
sudo touch /etc/r503d/allow-pair
sudo r503d --pair # plaintext-key rotation
# - or -
sudo r503d --pair --seal-tpm # TPM-sealed rotation
sudo systemctl start r503d
Stimmen Sie mit Ihrem ursprünglichen Pairing-Pfad überein. Wenn Sie ursprünglich --seal-tpm verwendet haben, rotieren Sie mit --seal-tpm — andernfalls setzt die Rotation Sie stillschweigend auf einen Klartext-Schlüssel auf der Festplatte zurück.
Wenn Sie --pair --seal-tpm verwendet und später etwas geändert haben, das PCR7 misst (Secure Boot aus-/eingeschaltet, neuer MOK eingeschrieben, Festplatte in ein anderes Gehäuse verschoben), weigert sich der Daemon zu starten, mit einer Journalmeldung über TPM_RC_POLICY_FAIL. Die Wiederherstellung erfolgt mit einem Befehl:```bash
sudo bash pcside/daemon/dist/reseal-tpm.sh
Das Skript stoppt `r503d`, flasht `firmware/r503fp_wipe/` erneut, um das Nano-EEPROM zu löschen, flasht die Haupt-Firmware erneut, erstellt `/etc/r503d/allow-pair`, führt `r503d --reseal-tpm` aus, um einen neuen Schlüssel zu generieren, der an das *aktuelle* PCR7 gebunden ist, und startet den Daemon neu. Wanduhrzeit: ~90 Sekunden. Eingeschriebene Finger bleiben erhalten – die Vorlagen befinden sich im Flash des R503-Sensors, nicht im Nano.
Das Skript benötigt `arduino-cli`. Wenn es im `$HOME/.local/bin`-Verzeichnis des Benutzers installiert ist, wird es automatisch über `$SUDO_USER` erkannt; andernfalls setzen Sie `ARDUINO_CLI=/vollständiger/Pfad/zu/arduino-cli` vor dem Ausführen.
### Wiederherstellung: verlorenes `state.json` (Zähler-Desynchronisation)
Wenn der Host-Key intakt ist, aber `/var/lib/r503d/state.json` fehlt oder zurückgesetzt wurde (alte Sicherung wiederhergestellt, versehentliches rm), fällt der Zähler des Daemons hinter das `last_seen` des Nano zurück und jeder gerahmte Befehl prallt mit `ERR replay` ab. `r503d --status` zeigt dies an; die Korrektur besteht aus einem Befehl:```bash
sudo systemctl stop r503d
sudo r503d --resync # reads Nano last_seen, sets host counter to last_seen+1
sudo systemctl start r503d
Kein erneutes Pairing, kein Reflash — der Schlüssel bewegt sich nie. Die status-Abfrage, auf die --resync
angewiesen ist, ist nicht authentifiziert, aber sie kann den Host-Zähler nur vorwärts bewegen,
um dem zu entsprechen, was der Nano bereits übergeben hat, sodass sie niemals einen alten Frame
wiederverwendbar machen kann (schlimmstenfalls erzwingt ein lügender MITM ein weiteres ERR replay,
was er bereits durch das Verfälschen von Frames tun konnte). Siehe SPEC.md §13.11.
Das authentifizierte --unpair benötigt den Schlüssel zur Autorisierung. Wenn alle
Kopien auf der Festplatte weg sind (Festplattenabsturz, versehentliches rm, sowohl key als auch key.bak
gelöscht oder key.tpm-Blob verloren), benötigen Sie die Reflash-to-Wipe-Notluke —
dasselbe Verfahren, das dist/reseal-tpm.sh für den oben erwähnten Fall der PCR7-Änderung automatisiert:```bash
sudo systemctl stop r503d
sudo arduino-cli upload --fqbn arduino:avr:nano:cpu=atmega328 --port /dev/r503 firmware/r503fp_wipe/
sudo arduino-cli upload --fqbn arduino:avr:nano:cpu=atmega328 --port /dev/r503 firmware/r503fp/ sudo touch /etc/r503d/allow-pair sudo r503d --pair sudo systemctl start r503d
Falls `sudo arduino-cli` den Fehler 'Befehl nicht gefunden' meldet (arduino-cli befindet sich in Ihrem `~/.local/bin`, nicht im `PATH` von root), führen Sie es als `sudo env "PATH=$PATH" arduino-cli …` aus oder geben Sie den absoluten Pfad an.
Dies ist keine Hintertür, die ein Angreifer nutzen kann: Für ein erneutes Pairing ist root auf dem Host erforderlich (die Opt-in-Datei und die `--pair`-CLI benötigen beide root), daher kann ein neu geflashtes Nano nicht als vertrauenswürdig eingestuft werden, ohne dass Sie bereits root sind.
### Uninstall```bash
sudo bash pcside/daemon/dist/uninstall.sh
Alles rückgängig machen, fprintd entsperren, /var/lib/r503d/ (Schlüssel,
Zustand, Benutzer) für eine spätere Neuinstallation belassen. Löschen Sie dieses
Verzeichnis manuell, wenn Sie einen wirklich sauberen Zustand wünschen.
Der Arduino führt eine Firmware mit kleinem ASCII-Protokoll (firmware/r503fp/)
aus, die das native binäre R30x-Protokoll („Sync Word“) des R503 auf seiner
UART-Seite spricht und mit dem Host über USB-CDC zeilenorientierte Textbefehle
austauscht: ping, info, enroll N, verify, delete N, clear,
led off. Vollständiges v1-Protokoll in SPEC.md §5.
Seit fw=1.0 (Meilenstein E der v2-Arbeit mit authentifiziertem Kanal) ist jeder
Befehl und jede Antwort in einen Rahmen C <Zähler> <Körper> M <MAC> /
R <Zähler> <Seq> <Körper> M <MAC> eingebettet, MAC-gesichert mit SipHash-2-4 über einen
TOFU-gepaarten 128-Bit-Schlüssel. Der Nano führt einen verschleißnivellierten monotonen Zähler
im EEPROM; der Daemon führt einen passenden Zähler in /var/lib/r503d/state.json.
Wiederholungsversuche (firmware-seitig incoming <= last_seen) werden als
ERR replay abgewiesen; manipulierte Rahmen erhalten ERR mac_invalid. Vollständige Spezifikation,
Bedrohungsmodell und bekannte Einschränkungen in SPEC.md §13.
Der Rust-Daemon (r503d) spricht D-Bus auf net.reactivated.Fprint — bitgenau
die gleiche Schnittstelle, die das vorgeschaltete fprintd bereitstellt — so funktioniert jeder
fprintd-Client unverändert. Eine JSON-Datei unter /var/lib/r503d/users.json bildet
(Benutzer, Finger) auf Slot-Indizes im internen Flash des R503 ab.
Layout:``` firmware/r503fp/ Arduino firmware (v2 framed ASCII protocol) firmware/r503fp_wipe/ Emergency one-shot EEPROM wipe (lost-key recovery) firmware/* Diagnostic / development sketches (ping, loopback, ...) pcside/daemon/ Rust daemon (the fprintd replacement) pcside/daemon/src/{crypto,framing,keystore,state,pairing}.rs v2 wire protocol implementation pcside/daemon/src/auth.rs caller-identity gating for D-Bus methods pcside/daemon/dist/ udev rule, systemd unit, polkit + bus policy, install scripts docs/ Decision logs + troubleshooting SPEC.md Full architecture + protocol spec (§13 = v2 auth)
## Sicherheitsmodell — Kurzübersicht
Die Authentifizierung auf Übertragungsebene zielt auf eine spezifische Bedrohung ab –
**„evil maid mit fünf Minuten und einem zusätzlichen Nano“** sowie einen feindlichen lokalen
Prozess auf `/dev/r503` – nicht auf staatliche Akteure oder Hardware-Angreifer mit
Laboren. Einsatz auf einem Einzelbenutzer-Desktop mit einer dokumentierten Ausnahmeliste.
Das vollständige Bedrohungsmodell befindet sich in [`SPEC.md` §13.1](https://github.com/matpb/linux-fingerprint-r503/blob/main/SPEC.md); die Implementierungs-
und Überprüfungsnachweise in
[`docs/REVIEW-2026-05-28.md`](https://github.com/matpb/linux-fingerprint-r503/blob/main/docs/REVIEW-2026-05-28.md). Ein separates
Adversarial-Privilege-Escalation-Audit (2026-05-28) und dessen anspruchsbezogener
Validierungs-/Behebungsdurchlauf befinden sich in
[`docs/SECURITY-AUDIT-2026-05-28.html`](https://github.com/matpb/linux-fingerprint-r503/blob/main/docs/SECURITY-AUDIT-2026-05-28.html)
und
[`docs/SECURITY-AUDIT-2026-05-28-VALIDATION.html`](https://github.com/matpb/linux-fingerprint-r503/blob/main/docs/SECURITY-AUDIT-2026-05-28-VALIDATION.html).
**Geschützt:**
- Hot-Swap des Nano durch eine feindliche Einheit (kein Schlüssel → alle Frames bestehen die MAC-Prüfung nicht).
- Lokaler Prozess, der gefälschte Match-Antworten auf `/dev/r503` injiziert. Zwei Ebenen:
der Geräteknoten ist `root:root 0600` (udev-Regel) und der Daemon hält ihn mit
`TIOCEXCL`, sodass ein nicht-root-Prozess ihn nicht öffnen kann — und selbst wenn er
könnte, hat er keinen Schlüssel, sodass der Frame die MAC-Prüfung nicht besteht.
- Wiederholung aufgezeichneter `OK match=...`-Frames in einer zukünftigen Sitzung.
- Bit-Flip-Manipulation eines beliebigen Frame-Felds (konstanter MAC-Vergleich).
- Counter-Exhaustion-Brick: Ein Peer (oder ein einmaliger MITM während `--resync`),
der den monotonen Zähler auf `u64::MAX` treibt und den Kanal dauerhaft blockiert,
wird durch eine reservierte Zählerobergrenze verhindert, die auf beiden Seiten
durchgesetzt wird (`fw=1.1+`; SPEC §13.4 / 2026-05-28 Audit DoS-2).
- Local-User-Denial-of-Service des Sensors: Ein einzelnes Capture-Slot-Gate begrenzt
die laufenden Enroll/Verify-Arbeiten, und die Delete-Pfade sind aktionsgesteuert,
sodass eine `Start`/`Stop`- (oder Concurrent-Delete-)Flut die Authentifizierung
nicht blockieren kann.
- Cross-User-Fingerabdruck-Hinterlegung / Löschen / Aufzählung durch einen lokalen
Nicht-Root-Benutzer (z.B. `mallory` ruft `Claim "root"` auf und registriert dann
ihren eigenen Finger) — Die Identität des Aufrufers wird bei jeder D-Bus-Methode,
die `username` annimmt, überprüft, und die System-Bus-Richtlinie verweigert
Nicht-`wheel`-Aufrufern auf der Broker-Ebene den Zugriff.
- **Offline-Disk-Angriffe auf den Host-Key** *in Kombination mit `--seal-tpm`*:
der Schlüssel auf der Festplatte ist TPM2-versiegelt an PCR7, sodass `dd` einer
nicht gemounteten Partition oder SSD-Tausch in einen feindlichen Host nur
Ciphertext ergibt. Entsiegelt wird nur auf demselben Rechner unter derselben
Secure-Boot-Richtlinie. Siehe [SPEC §13.12](https://github.com/matpb/linux-fingerprint-r503/blob/main/SPEC.md).
**Nicht geschützt:**
- Host-Root-Kompromittierung (Schlüssel befindet sich in `/var/lib/r503d/key`,
`0600 root:root`). Root auf einem laufenden Host kann auch die TPM-versiegelte
Variante entsiegeln – die Versiegelung schwächt *Offline*-Angriffe ab, nicht
Online-Angriffe.
- Physischer Angriff auf den Nano (EEPROM-Auslesen ~30 Sekunden mit ISP;
Chip-Dekap; usw.).
- Firmware-Reflash-Angriff (der Arduino-Bootloader hat keine Signierung – aber
das erneute Pairing erfordert Root auf dem Host, sodass ein zurückgesetzter
Nano ohne Host-Kompromittierung ohnehin nicht in Vertrauen gebracht werden kann).
- R503-seitige Kompromittierung (R30x-Protokoll hat gar keine Authentifizierung;
außerhalb unseres Rahmens).
- **Crypto-Haltung.** SipHash-2-4 MACs, 128-Bit gemeinsamer Schlüssel, 64-Bit
MAC-Ausgabe, domain-getrennte MAC-Eingaben. Zwei unabhängige Implementierungen
(handgeschriebenes C++ auf dem AVR mit Boot-Zeit-KAT-Selbsttest;
handgeschriebenes Rust auf dem Host, bitweise kreuzvalidiert gegen die
Drittanbieter-Crate `siphasher` auf 1024 Zufallsvektoren in CI). Host-MAC-Vergleich
verwendet `subtle::ConstantTimeEq`. Wire-Parser werden bei jedem CI-Lauf
property-fuzzed (~135.000 Eingaben). `cargo audit` sauber. SipHash-Schlüssel in
`zeroize::Zeroizing<...>` eingewickelt, sodass er beim Drop gelöscht wird (ebenso
wie die MAC-Eingabepuffer pro Frame). Ein `cargo fuzz`
libFuzzer-Target befindet sich unter `pcside/daemon/fuzz/` für lange
Korpusläufe auf Nightly. Kein kostenpflichtiges menschliches Drittaudit – das
wäre immer noch wertvoll, PRs willkommen.
Vollständiges Bedrohungsmodell mit Begründung: [`SPEC.md` §13.1](https://github.com/matpb/linux-fingerprint-r503/blob/main/SPEC.md).
## Einschränkungen
- **Mehrbenutzer funktioniert, aber nur für `wheel`-Mitglieder.** Die Identität des
Aufrufers wird bei jeder D-Bus-Methode überprüft, die einen `username` entgegennimmt
(`Claim`, `EnrollStart`, `VerifyStart`, `ListEnrolledFingers`,
`DeleteEnrolledFingers`); Selbstanfragen und `uid 0` (PAM) werden stillschweigend
akzeptiert, Cross-User von einem Nicht-Root-Aufrufer wird mit
`net.reactivated.Fprint.Error.PermissionDenied` verweigert. Die System-Bus-Richtlinie
schränkt weiter ein, welche Konten überhaupt ein Gespräch beginnen können: nur
`root`- und `wheel`-Mitglieder erreichen den Daemon, jeder andere erhält
`org.freedesktop.DBus.Error.AccessDenied` auf der Broker-Ebene.
Cross-User-Enroll nötig? Werden Sie root: `sudo fprintd-enroll target-user`.
Möchten Sie das Cross-User-Gate für einen Kiosk / ein Mehrbenutzer-Labor lockern?
Legen Sie eine JS-Regel in `/etc/polkit-1/rules.d/` ab, die auf
[`net.reactivated.fprint.device.setusername`](https://gitlab.freedesktop.org/libfprint/fprintd/-/blob/master/src/net.reactivated.fprint.device.policy.in)
abzielt — der Aktionsname spiegelt upstream fprintd wortwörtlich wider.
- **Ein Lesegerät.** Der Daemon stellt ein einzelnes Device-Objekt auf D-Bus bereit.
Multi-Reader-Setups benötigen eine Erweiterung des Managers.
- **Kein `PropertiesChanged`-Emit** für die Hinweiseigenschaften `finger-present` /
`finger-needed`. Jeder gängige fprintd-Client (PAM, KDE-Einstellungen, GNOME)
verwendet `EnrollStatus` / `VerifyStatus`-Signale (die ausgesendet werden), nicht
diese abgefragten Hinweise — aber ein strenger Client, der
`Get + PropertiesChanged` durchführt, wird veraltete Werte sehen.
- **Einzelner Nano = Single Point of Failure.** Wenn der Nano stirbt, ist der
Fingerabdruck-Login weg, bis Sie einen Ersatz neu flashen und neu pairen. Halten Sie
eine Passwort-Authentifizierungsmethode als Backup aktiviert.
- **State.json-Verlust ist mit einem Befehl behebbar.** Wenn `state.json` verloren geht,
während die Firmware noch einen hohen `last_seen`-Wert hat, stößt der Daemon beim
ersten Senden auf `ERR replay`. Führen Sie `sudo r503d --resync` aus, um den Zähler
des Nano auszulesen und den Host neu auszurichten — kein erneutes Pairing erforderlich.
Siehe [`SPEC.md` §13.11](https://github.com/matpb/linux-fingerprint-r503/blob/main/SPEC.md).
## Fehlerbehebung```bash
# Daemon logs:
sudo journalctl -u r503d.service -f
# Confirm the sensor enumerates correctly:
ls -l /dev/r503
busctl --system call net.reactivated.Fprint /net/reactivated/Fprint/Device/0 \
net.reactivated.Fprint.Device ListEnrolledFingers s ""
# Confirm fprintd is masked and r503d owns the bus name:
systemctl is-enabled fprintd # should print "masked"
busctl --system list | grep -i fprint
Wenn der Daemon nicht startet oder der Sensor nie antwortet, ist die häufigste Lösung die Verkabelung – siehe SPEC.md §3, insbesondere die „no voltage divider“-Notiz in §3.1. Ein ausführlicheres Handbuch findest du in docs/TROUBLESHOOTING.md.
MIT – siehe LICENSE.
fprintd-Projekt – für die Gestaltung einer sauberen D-Bus-Schnittstelle, gegen die dieser Daemon implementiert werden konnte, ohne jemals den Quellcode von libfprint lesen zu müssen./etc/dbus-1/system.d/net.reactivated.Fprint.conf) — nur Mitglieder von root und wheel können mit dem Daemon sprechen; alle anderen erhalten AccessDenied am Broker, bevor der Daemon den Aufruf siehtfprintd.servicer503d.service