fix: security and correctness audit fixes (v0.4.1)
PAM conv callback: check msg_style (password only for ECHO_OFF), handle strdup OOM with proper cleanup, null-check PAM handle. Fingerprint: self-wire D-Bus g-signal in start() via Rc<RefCell<>> and connect_local — VerifyStatus signals are now actually dispatched. VerifyStop before VerifyStart in restart_verify. Lockscreen: password entry stays active after faillock threshold (PAM decides lockout, not UI), use Zeroizing<String> from GTK entry. Release builds exit(1) without ext-session-lock-v1 support. Config: fingerprint_enabled as Option<bool> so empty user config does not override system config. Dead code: remove unused i18n strings and fingerprint accessors, parameterize faillock_warning max_attempts.
This commit is contained in:
+64
-26
@@ -3,6 +3,8 @@
|
||||
|
||||
use gio::prelude::*;
|
||||
use gtk4::gio;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
const FPRINTD_BUS_NAME: &str = "net.reactivated.Fprint";
|
||||
const FPRINTD_MANAGER_PATH: &str = "/net/reactivated/Fprint/Manager";
|
||||
@@ -126,24 +128,31 @@ impl FingerprintListener {
|
||||
}
|
||||
}
|
||||
|
||||
/// Whether the listener is currently running.
|
||||
pub fn is_running(&self) -> bool {
|
||||
self.running
|
||||
}
|
||||
|
||||
/// Start listening for fingerprint verification.
|
||||
pub fn start<F, G>(&mut self, username: &str, on_success: F, on_failure: G)
|
||||
where
|
||||
/// Connects the D-Bus g-signal handler internally. The `listener` parameter
|
||||
/// must be the same `Rc<RefCell<FingerprintListener>>` that owns `self`.
|
||||
pub fn start<F, G>(
|
||||
listener: &Rc<RefCell<FingerprintListener>>,
|
||||
username: &str,
|
||||
on_success: F,
|
||||
on_failure: G,
|
||||
) where
|
||||
F: Fn() + 'static,
|
||||
G: Fn() + 'static,
|
||||
{
|
||||
let proxy = match &self.device_proxy {
|
||||
Some(p) => p,
|
||||
None => return,
|
||||
let proxy = {
|
||||
let inner = listener.borrow();
|
||||
match inner.device_proxy.clone() {
|
||||
Some(p) => p,
|
||||
None => return,
|
||||
}
|
||||
};
|
||||
|
||||
self.on_success = Some(Box::new(on_success));
|
||||
self.on_failure = Some(Box::new(on_failure));
|
||||
{
|
||||
let mut inner = listener.borrow_mut();
|
||||
inner.on_success = Some(Box::new(on_success));
|
||||
inner.on_failure = Some(Box::new(on_failure));
|
||||
}
|
||||
|
||||
// Claim the device
|
||||
let args = glib::Variant::from((&username,));
|
||||
@@ -178,12 +187,42 @@ impl FingerprintListener {
|
||||
return;
|
||||
}
|
||||
|
||||
self.running = true;
|
||||
// Connect the g-signal handler on the proxy to dispatch VerifyStatus
|
||||
let listener_weak = Rc::downgrade(listener);
|
||||
let signal_id = proxy.connect_local("g-signal", false, move |values| {
|
||||
// g-signal arguments: (proxy, sender_name, signal_name, parameters)
|
||||
let signal_name: String = match values[2].get() {
|
||||
Ok(v) => v,
|
||||
Err(_) => return None,
|
||||
};
|
||||
if signal_name.as_str() != "VerifyStatus" {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Note: Signal handling is set up by the caller via connect_g_signal()
|
||||
// because FingerprintListener is not an Rc and the g-signal callback
|
||||
// needs to reference mutable state. The caller (lockscreen.rs) will
|
||||
// connect the proxy's "g-signal" and call on_verify_status().
|
||||
let params = match values[3].get::<glib::Variant>() {
|
||||
Ok(v) => v,
|
||||
Err(_) => return None,
|
||||
};
|
||||
|
||||
let status = params
|
||||
.child_value(0)
|
||||
.get::<String>()
|
||||
.unwrap_or_default();
|
||||
let done = params
|
||||
.child_value(1)
|
||||
.get::<bool>()
|
||||
.unwrap_or(false);
|
||||
|
||||
if let Some(listener_rc) = listener_weak.upgrade() {
|
||||
listener_rc.borrow_mut().on_verify_status(&status, done);
|
||||
}
|
||||
|
||||
None
|
||||
});
|
||||
|
||||
let mut inner = listener.borrow_mut();
|
||||
inner.signal_id = Some(signal_id);
|
||||
inner.running = true;
|
||||
}
|
||||
|
||||
/// Process a VerifyStatus signal from fprintd.
|
||||
@@ -228,6 +267,14 @@ impl FingerprintListener {
|
||||
/// Restart fingerprint verification after a completed attempt.
|
||||
fn restart_verify(&self) {
|
||||
if let Some(ref proxy) = self.device_proxy {
|
||||
// VerifyStop before VerifyStart to avoid D-Bus errors
|
||||
let _ = proxy.call_sync(
|
||||
"VerifyStop",
|
||||
None,
|
||||
gio::DBusCallFlags::NONE,
|
||||
-1,
|
||||
gio::Cancellable::NONE,
|
||||
);
|
||||
let args = glib::Variant::from((&"any",));
|
||||
if let Err(e) = proxy.call_sync(
|
||||
"VerifyStart",
|
||||
@@ -269,15 +316,6 @@ impl FingerprintListener {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a reference to the device proxy for signal connection.
|
||||
pub fn device_proxy(&self) -> Option<&gio::DBusProxy> {
|
||||
self.device_proxy.as_ref()
|
||||
}
|
||||
|
||||
/// Store the signal handler ID for cleanup.
|
||||
pub fn set_signal_id(&mut self, id: glib::SignalHandlerId) {
|
||||
self.signal_id = Some(id);
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
||||
Reference in New Issue
Block a user