fix: drop pam_acct_mgmt from password and FP paths (v0.6.13)
Update PKGBUILD version / update-pkgver (push) Successful in 3s
Update PKGBUILD version / update-pkgver (push) Successful in 3s
The PAM stack only ever had `auth include login` — no account module. auth.rs nevertheless called pam_acct_mgmt after pam_authenticate, which fell back to /etc/pam.d/other (pam_deny) and rejected every password. On the FP side, the same call was wrapped in a spawn_blocking + 2s resume_async retry path that triggered a use-after-free in gtk_window_destroy (20+ SIGSEGVs in 6 days). - auth.rs: remove pam_acct_mgmt extern + call; return pam_authenticate result directly. Lockout still works via pam_faillock in the auth stack. - auth.rs: drop check_account() and its tests (FP path no longer needs it). - lockscreen.rs::start_fingerprint: on success go straight to label.set_text + fp.stop() + cb(); no PAM acct check, no resume retry. - fingerprint.rs: remove resume_async() — no caller left. - config/moonlock-pam: keep single `auth include login` line, matching swaylock/gtklock pattern. - CLAUDE.md, DECISIONS.md updated.
This commit is contained in:
@@ -175,29 +175,6 @@ impl FingerprintListener {
|
||||
Self::begin_verification(listener, username).await;
|
||||
}
|
||||
|
||||
/// Resume fingerprint verification after a transient interruption (e.g. failed
|
||||
/// PAM account check). Reuses previously stored callbacks. Re-claims the device
|
||||
/// and restarts verification from scratch. Awaits any in-flight VerifyStop +
|
||||
/// Release before re-claiming the device so fprintd does not reject the Claim
|
||||
/// while the previous session is still being torn down.
|
||||
pub async fn resume_async(
|
||||
listener: &Rc<RefCell<FingerprintListener>>,
|
||||
username: &str,
|
||||
) {
|
||||
// Drain in-flight cleanup so the device is actually released before Claim.
|
||||
// Without this, a fast resume after on_verify_status's fire-and-forget
|
||||
// cleanup races the Release call and fprintd returns "already claimed".
|
||||
let proxy = listener.borrow_mut().take_cleanup_proxy();
|
||||
if let Some(proxy) = proxy {
|
||||
Self::perform_dbus_cleanup(proxy).await;
|
||||
}
|
||||
// Deliberately do NOT reset failed_attempts here. An attacker with sensor
|
||||
// control could otherwise cycle verify-match → check_account fail → resume,
|
||||
// and the 10-attempt cap would never trigger. The counter decays only via
|
||||
// a fresh lock session (listener construction).
|
||||
Self::begin_verification(listener, username).await;
|
||||
}
|
||||
|
||||
/// Claim device, start verification, and connect D-Bus signal handler.
|
||||
/// Assumes device_proxy is set and callbacks are already stored.
|
||||
async fn begin_verification(
|
||||
@@ -366,11 +343,6 @@ impl FingerprintListener {
|
||||
|
||||
/// Disconnect the signal handler and clear running flags. Returns the proxy
|
||||
/// the caller should use for the async D-Bus cleanup (VerifyStop + Release).
|
||||
///
|
||||
/// Split into a sync part (signal disconnect, flags) and an async part
|
||||
/// (`perform_dbus_cleanup`) so callers can either spawn the async work
|
||||
/// fire-and-forget (via `cleanup_dbus`) or await it to serialize with a
|
||||
/// subsequent Claim (via `resume_async`).
|
||||
fn take_cleanup_proxy(&mut self) -> Option<gio::DBusProxy> {
|
||||
self.running = false;
|
||||
self.running_flag.set(false);
|
||||
|
||||
Reference in New Issue
Block a user