Files
fingerprint-switch/README.md
T

7.6 KiB
Raw Blame History

fingerprint-switch

A Rust tool for selecting a fingerprint reader through fprintd, plus optional lid-based routing for normal login, lock-screen and sudo authentication that already uses fprintd. Uses the installed libfprint drivers and Polkit permissions.

Built for this laptop's two readers:

Role USB ID libfprint driver fprintd name
Internal 27c6:609c goodixmoc Goodix MOC Fingerprint Sensor
External 3274:8012 mafpmoc MAFP MOC Fingerprint Sensor

The USB sensor is already supported by libfprint 1.94.100, installed on this Aurora 44 machine. A new USB driver is unnecessary. These are match-on-chip readers; this tool does not export fingerprint images or implement matching.

Build and use

cargo build --release --locked
./target/release/fingerprint-switch list
./target/release/fingerprint-switch status
./target/release/fingerprint-switch probe --sensor external

Run these as your normal desktop user. probe opens and releases the reader without enrolling. Commands that access fprintd need the host's system D-Bus; run them outside a restricted sandbox. Polkit may request authentication.

Enroll one finger on the external sensor, then verify it:

./target/release/fingerprint-switch enroll --sensor external \
  --finger right-index-finger --allow-template-reset
./target/release/fingerprint-switch verify --sensor external

The template-reset flag acknowledges a real driver limitation. In libfprint 1.94.100, the mafpmoc enrollment path unconditionally sends command 0x0d, the same command used to clear all device storage. Thus enrollment can erase all previously stored templates on the external sensor, including other users' or Windows templates. It does not erase the separate Goodix reader. This was confirmed from source, not by erasing this device. Use one enrolled finger on the external reader with this driver; enrolling a second can invalidate the first. The tool requires the flag for MAFP/Microarray readers even when fprintd lists no prints, because device storage may contain templates from another installation.

Follow the prompts and lift your finger between samples. Enrollment defaults to 120 seconds, verification to 30; use --timeout SECONDS (1–600) to change this. Ctrl-C cancels and releases the reader. Only an explicit successful completion produces exit code 0; no-match, cancellation and timeout produce nonzero exits.

Other examples:

./target/release/fingerprint-switch verify --sensor internal
./target/release/fingerprint-switch verify --sensor auto
./target/release/fingerprint-switch verify --sensor 'MAFP MOC Fingerprint Sensor'

auto reads the lid state at the start of the command: closed prefers external, open prefers internal, and an absent preferred reader falls back to the other. Explicit selection never silently falls back. Duplicate device names require a D-Bus path from list; paths may change when fprintd restarts. Fingerprints must be enrolled separately on each reader. --user USER selects another account subject to fprintd's normal permissions; omitting it uses the calling user.

Automatic routing for login and sudo

CLI selection affects only that invocation. Stock pam_fprintd chooses the reader with the most enrolled fingers; it does not use the CLI's selected reader.

The optional system service checks the lid and USB presence every second and writes a root-owned environment file under /run/fingerprint-switch. A fprintd service drop-in reads FP_DRIVERS_ALLOWLIST from this file. It allows the internal driver with the lid open and the external driver with it closed, falling back to the connected reader if the preferred one is missing. With neither connected it allows both drivers for hotplug discovery. If lid state is unavailable, it prefers the internal reader and logs the condition.

Only the selected driver is exposed through fprintd in automatic mode. Both devices remain physically connected. Changes queue a restart of an active fprintd; they do not start an idle fprintd. Switching can cancel an enrollment or authentication already in progress. The next attempt uses the new reader. Keep the lid and USB connection stable while enrolling.

After enrolling and verifying both readers, install the optional integration:

sudo ./scripts/install.sh
fingerprint-switch status
journalctl -u fingerprint-switch -n 30 --no-pager

The installer copies the built binary to /usr/local/bin, installs its own systemd service and fprintd drop-in, and enables the watcher. It does not replace libfprint, edit PAM, change suspend behavior or delete enrollment data. Existing fingerprint-enabled authentication flows use the selected reader. Applications that access USB directly are outside this routing mechanism. The allowlist operates per driver, so it is intended for this Goodix-plus-Microarray pair. The installer restarts an already-running fprintd once to apply the new drop-in. The runtime environment is preserved across watcher stops/restarts, and is removed during uninstall or reboot. If the watcher is interrupted between writing a selection and restarting fprintd, force application with sudo systemctl try-restart fprintd.service.

Manual overrides, stored in /etc/fingerprint-switch/mode:

sudo fingerprint-switch mode external  # only Microarray, regardless of lid
sudo fingerprint-switch mode internal  # only Goodix, regardless of lid
sudo fingerprint-switch mode both      # expose both for enrollment/CLI selection
sudo fingerprint-switch mode auto      # return to lid-based routing

The installed watcher applies changes within a few seconds. In both mode PAM returns to its usual enrollment-count selection; it does not listen on both readers simultaneously. If the service is not installed/running, mode only saves a preference. Automatic routing does not check whether the current user has enrolled a finger on the selected reader; enroll first. It also cannot make an inaccessible built-in reader usable when the lid is closed and USB unplugged; use the normal password fallback in that situation.

Rollback:

sudo ./scripts/uninstall.sh

This removes the watcher and its drop-in, restarts an active fprintd to restore stock discovery, and preserves all enrollments. No password/PAM settings change.

Validation and sources

cargo test --locked
cargo clippy --all-targets --locked -- -D warnings
cargo fmt --check
bash -n scripts/install.sh scripts/uninstall.sh

Tests use dbus-daemon to run isolated mock buses and cover reader-selection policy and D-Bus operation handling without storing biometrics. Run them outside a sandbox that blocks local sockets. Full enrollment/verification needs a person touching the sensor; lid-based system routing must also be tested after opting into installation. See VALIDATION.md for the checks actually performed on this machine.

research/ contains ignored, unmodified upstream checkouts used during the investigation; they are not dependencies of this program.