Files

158 lines
7.6 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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
```sh
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:
```sh
./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:
```sh
./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:
```sh
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`:
```sh
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:
```sh
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
```sh
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.
- [Official supported-device list](https://fprint.freedesktop.org/supported-devices.html)
- [libfprint v1.94.100 mafpmoc source](https://gitlab.freedesktop.org/libfprint/libfprint/-/blob/v1.94.100/libfprint/drivers/mafpmoc/mafpmoc.c)
- [Commit introducing unconditional enrollment clear](https://gitlab.freedesktop.org/libfprint/libfprint/-/commit/67649a0efde02211b89a8c8153d37d797bd2ca6f)
- [fprintd Device D-Bus API](https://fprint.freedesktop.org/fprintd-dev/Device.html)
- [PAM device-selection implementation](https://gitlab.freedesktop.org/libfprint/fprintd/-/blob/v1.94.5/pam/pam_fprintd.c)
- [UPower lid properties](https://upower.freedesktop.org/docs/UPower/)
`research/` contains ignored, unmodified upstream checkouts used during the
investigation; they are not dependencies of this program.