feat(fingerprint): password OR fingerprint in parallel at one prompt
Some checks failed
Check / eval (push) Failing after 2m45s
Some checks failed
Check / eval (push) Failing after 2m45s
Bernardo promoted the PROPOSED item live: with fingerprint PAM on, sudo/login should accept whichever factor comes first instead of pam_fprintd's wait-for-the-reader-then-password. Stock PAM cannot express parallel factors (linux-pam#301), so this packages pam-fprint-grosshack v0.3.0 (pkgs/, pinned from GitLab — the field-standard fprintd fork), source-reviewed before packaging: every failure path (no reader, no prints, fprintd absent/hung, timeout, password typed) returns PAM_AUTHINFO_UNAVAIL and falls through; a typed password is only ferried via PAM_AUTHTOK to the stock `auth sufficient pam_unix.so … try_first_pass` rule — the module never validates passwords itself, so it cannot lock out password login. New option nomarchy.hardware.fingerprint.parallel, default TRUE (the better UX is what opting into fingerprint PAM buys; false = stock sequential). Wiring swaps the modulePath of stock fprintd's rule slot (mkForce) so the sufficient-before-pam_unix ordering is inherited, not recomputed. README + downstream template rows added. Verified: V2 — checks.hardware-toggles extended to three nodes, green: parallel node asserts the grosshack auth line precedes pam_unix in /etc/pam.d/sudo and that with NO reader a correct password still passes sudo while a wrong one fails (the lockout-safety invariant); seqpam node gets stock pam_fprintd and no grosshack; nopam gets neither. flake check + option-docs + template-sot green. V3 pending (HARDWARE-QUEUE, AMD dev box): the real type-or-touch race, fprintd-stopped fallback, hyprlock/greeter after a fingerprint win. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
36
flake.nix
36
flake.nix
@@ -93,6 +93,7 @@
|
||||
# switch can refresh a broken system-package nomarchy-pull.
|
||||
# Includes nomarchy-what-changed (generation readability, #82).
|
||||
nomarchy-lifecycle = final.callPackage ./pkgs/nomarchy-lifecycle { };
|
||||
pam-fprint-grosshack = final.callPackage ./pkgs/pam-fprint-grosshack { };
|
||||
};
|
||||
|
||||
nixosModules.nomarchy = {
|
||||
@@ -539,7 +540,11 @@
|
||||
# what they SET (kernel cmdline, fprintd, PAM). Real hardware
|
||||
# behaviour (firmware/driver/device) needs bare metal and is out of
|
||||
# scope here. Imports only hardware.nix, so the VM stays minimal.
|
||||
# Two nodes: pam=true must wire pam_fprintd; pam=false must NOT
|
||||
# Three nodes: pam=true wires the PARALLEL module by default
|
||||
# (pam_fprintd_grosshack in stock fprintd's rule slot, before
|
||||
# pam_unix) and password-only auth must still work with no
|
||||
# reader present — the lockout-safety invariant; parallel=false
|
||||
# wires stock sequential pam_fprintd; pam=false wires neither
|
||||
# (NixOS defaults fprintAuth from fprintd.enable — we force off).
|
||||
hardware-toggles = pkgs.testers.runNixOSTest {
|
||||
name = "nomarchy-hardware-toggles";
|
||||
@@ -552,6 +557,17 @@
|
||||
fingerprint = { enable = true; pam = true; };
|
||||
npu.enable = true;
|
||||
};
|
||||
users.users.alice = {
|
||||
isNormalUser = true;
|
||||
password = "t0ps3cret";
|
||||
extraGroups = [ "wheel" ];
|
||||
};
|
||||
};
|
||||
seqpam = { ... }: {
|
||||
imports = [ ./modules/nixos/hardware.nix ];
|
||||
nomarchy.hardware.fingerprint = {
|
||||
enable = true; pam = true; parallel = false;
|
||||
};
|
||||
};
|
||||
nopam = { ... }: {
|
||||
imports = [ ./modules/nixos/hardware.nix ];
|
||||
@@ -564,7 +580,23 @@
|
||||
assert "amd_pstate=active" in cmdline, cmdline
|
||||
assert "i915.enable_guc=3" in cmdline, cmdline
|
||||
machine.succeed("systemctl cat fprintd.service")
|
||||
machine.succeed("grep -q pam_fprintd /etc/pam.d/sudo")
|
||||
machine.succeed("grep -q pam_fprintd_grosshack /etc/pam.d/sudo")
|
||||
# The parallel rule must be an auth line ordered BEFORE
|
||||
# pam_unix — its typed password is only ferried to pam_unix.
|
||||
machine.succeed(
|
||||
"awk '/^auth/ && /pam_fprintd_grosshack/ {g=NR} "
|
||||
"/^auth/ && /pam_unix/ {u=NR} "
|
||||
"END {exit !(g && u && g < u)}' /etc/pam.d/sudo"
|
||||
)
|
||||
# Lockout safety: this VM has no fingerprint reader, so the
|
||||
# grosshack rule can only fail through — the password alone
|
||||
# must still authenticate sudo (and a wrong one must not).
|
||||
machine.succeed("su - alice -c 'echo t0ps3cret | sudo -S -k true'")
|
||||
machine.fail("su - alice -c 'echo wrongpw | sudo -S -k true'")
|
||||
|
||||
seqpam.wait_for_unit("multi-user.target")
|
||||
seqpam.succeed("grep -q pam_fprintd /etc/pam.d/sudo")
|
||||
seqpam.fail("grep -q pam_fprintd_grosshack /etc/pam.d/sudo")
|
||||
|
||||
nopam.wait_for_unit("multi-user.target")
|
||||
nopam.succeed("systemctl cat fprintd.service")
|
||||
|
||||
Reference in New Issue
Block a user