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:
+1
-37
@@ -427,52 +427,16 @@ pub fn start_fingerprint(
|
||||
let unlock_cb_fp = handles.unlock_callback.clone();
|
||||
|
||||
let fp_rc_success = fp_rc.clone();
|
||||
let fp_username = handles.username.clone();
|
||||
let on_success = move || {
|
||||
let label = fp_label_success.clone();
|
||||
let cb = unlock_cb_fp.clone();
|
||||
let fp = fp_rc_success.clone();
|
||||
let username = fp_username.clone();
|
||||
glib::idle_add_local_once(move || {
|
||||
let strings = load_strings(None);
|
||||
label.set_text(strings.fingerprint_success);
|
||||
label.add_css_class("success");
|
||||
// stop() is idempotent — cleanup_dbus() already ran inside on_verify_status,
|
||||
// but this mirrors the PAM success path for defense-in-depth.
|
||||
fp.borrow_mut().stop();
|
||||
|
||||
// Enforce PAM account policies (lockout, expiry) before unlocking.
|
||||
// Fingerprint auth bypasses pam_authenticate, so we must explicitly
|
||||
// check account restrictions via pam_acct_mgmt.
|
||||
glib::spawn_future_local(async move {
|
||||
let user = username.clone();
|
||||
let result = gio::spawn_blocking(move || {
|
||||
auth::check_account(&user)
|
||||
}).await;
|
||||
match result {
|
||||
Ok(true) => cb(),
|
||||
_ => {
|
||||
log::error!("PAM account check failed after fingerprint auth");
|
||||
let strings = load_strings(None);
|
||||
label.set_text(strings.wrong_password);
|
||||
label.remove_css_class("success");
|
||||
label.add_css_class("failed");
|
||||
// Restart FP verification after delay — the failure may be
|
||||
// transient (e.g. PAM module timeout). If the account is truly
|
||||
// locked, check_account will fail again on next match.
|
||||
glib::timeout_add_local_once(
|
||||
std::time::Duration::from_secs(2),
|
||||
move || {
|
||||
label.set_text(load_strings(None).fingerprint_prompt);
|
||||
label.remove_css_class("failed");
|
||||
glib::spawn_future_local(async move {
|
||||
FingerprintListener::resume_async(&fp, &username).await;
|
||||
});
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user