#!/usr/bin/env bash # Fingerprint state and the one privileged switch, for the Users page. # # Two independent facts make a working fingerprint login, and conflating them # is how the feature usually confuses people: fprintd must hold at least one # enrolled print (GNOME's Users panel owns that dialog, and Panama hands off # to it), and PAM must be told to ask the reader at all, which on Fedora is # authselect's `with-fingerprint` feature. This helper reports both and can # flip the second. # # Usage: # panama-fingerprint status -> {"reader":bool,"readerName":"","enrolled":[],"pamEnabled":bool,"error":""} # panama-fingerprint set-unlock on|off (prompts through panama-sudo/polkit) # # authselect is baseline Fedora (it manages PAM for the whole install), and # fprintd ships with Workstation; a machine with neither simply reports no # reader, which hides the card. set -uo pipefail PANAMA_PATH="${PANAMA_PATH:-$HOME/.local/share/Panama}" emit() { jq -cn \ --argjson reader "$1" \ --arg readerName "$2" \ --argjson enrolled "$3" \ --argjson pamEnabled "$4" \ --arg error "$5" \ '{reader: $reader, readerName: $readerName, enrolled: $enrolled, pamEnabled: $pamEnabled, error: $error}' } cmd_status() { command -v fprintd-list >/dev/null 2>&1 || { emit false "" '[]' false ""; return; } # fprintd-list both answers "is there a reader" (fprintd is bus-activated, # so this also copes with the daemon not running yet) and names the # enrolled fingers in one call. local listing # LC_ALL=C: the "no devices" match below reads fprintd's message, and a # translated daemon would turn every readerless non-English machine into # a permanent error card. if ! listing="$(LC_ALL=C timeout 10 fprintd-list "$USER" 2>&1)"; then # "No devices available" is the normal no-reader machine; anything # else is a real problem worth surfacing. if grep -qi 'no devices' <<<"$listing"; then emit false "" '[]' false "" else emit false "" '[]' false "fprintd did not answer: $(head -1 <<<"$listing")" fi return fi # "Fingerprints for user gib on FocalTech ... (press):" carries the reader # product name; " - #0: right-index-finger" lines carry the enrollment. local name enrolled pam name="$(sed -n 's/^Fingerprints for user [^ ]* on \(.*\) (\w*):$/\1/p' <<<"$listing" | head -1)" enrolled="$(sed -n 's/^ *- #[0-9]*: //p' <<<"$listing" | jq -Rn '[inputs]')" pam=false authselect current 2>/dev/null | grep -q 'with-fingerprint' && pam=true emit true "$name" "$enrolled" "$pam" "" } cmd_set_unlock() { local verb reason case "$1" in on) verb=enable-feature reason="Turning on fingerprint login: telling PAM (via authselect) to ask the fingerprint reader when unlocking" ;; off) verb=disable-feature reason="Turning off fingerprint login: telling PAM (via authselect) to stop asking the fingerprint reader" ;; *) echo 'panama-fingerprint set-unlock takes on|off' >&2; exit 1 ;; esac local sudo_cmd=(sudo) [[ -x "$PANAMA_PATH/bin/panama-sudo" ]] && sudo_cmd=( "$PANAMA_PATH/bin/panama-sudo" --reason "$reason" -- ) "${sudo_cmd[@]}" authselect "$verb" with-fingerprint } case "${1:-}" in status) cmd_status ;; set-unlock) [[ -n "${2:-}" ]] || { echo 'panama-fingerprint set-unlock takes on|off' >&2; exit 1; } cmd_set_unlock "$2" ;; *) echo 'usage: panama-fingerprint status | set-unlock on|off' >&2; exit 1 ;; esac