mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-08-24 07:06:32 +00:00
fix: settle the DRM probe before routing login to X11, and read seat0 fresh
Two findings from the #15792 review, both verified against the code: - drm_login_screen_seat0_username asked the cached probe, so a client arriving before warm_availability publishes its verdict read "no DRM" and, with allow-linux-headless=Y, try_start_x_session could start Xorg over a live Wayland greeter. Ask the probing form instead, and only after the cheap seat0 read says a Wayland greeter is actually there: a bounded definitive verdict is affordable on a login-time path. - get_supported_display_seat0_username trusted the seat0 values cached in DesktopManager::new(), which go stale across a logout or a fast user switch: a stale non-greeter name skipped the greeter probe and was returned as the supported display owner. Read seat0 fresh on every query; every call site is connection-time, so the extra loginctl read is cheap. Regression-tested on a real sddm Wayland greeter: capture streams the greeter, the RustDesk password dialog is the only prompt, and five typed characters appeared in the greeter password field over uinput with zero "Rejected unauthorized connection" lines in the service log.
This commit is contained in:
@@ -230,20 +230,20 @@ pub fn is_headless() -> bool {
|
||||
}
|
||||
|
||||
/// The Wayland greeter on seat0, if the DRM backend can capture and inject into it.
|
||||
///
|
||||
/// The cached probe, to match the routing gate in `Connection`: not yet settled answers false,
|
||||
/// which is what upstream does today.
|
||||
#[cfg(feature = "drm")]
|
||||
fn drm_login_screen_seat0_username() -> Option<String> {
|
||||
if !crate::server::drm_capturer::is_available_cached() {
|
||||
return None;
|
||||
}
|
||||
let values = get_values_of_seat0_with_gdm_wayland(&[0, 2]);
|
||||
if !is_gdm_user(&values[1])
|
||||
|| get_display_server_of_session(&values[0]) != DISPLAY_SERVER_WAYLAND
|
||||
{
|
||||
return None;
|
||||
}
|
||||
// The probing form, asked only once a Wayland greeter is on seat0: the cached probe answers
|
||||
// false while the warm-up is unsettled, and that would let try_start_x_session put Xorg over
|
||||
// a live greeter. This is a login-time path, so a bounded definitive verdict is affordable.
|
||||
if !crate::server::drm_capturer::is_available() {
|
||||
return None;
|
||||
}
|
||||
Some(values[1].clone())
|
||||
}
|
||||
|
||||
@@ -293,22 +293,25 @@ impl DesktopManager {
|
||||
}
|
||||
|
||||
fn get_supported_display_seat0_username(&self) -> Option<String> {
|
||||
// A Wayland greeter the DRM backend can serve is a supported display. Asked here and not in
|
||||
// `new()` because the seat0 read there hides greeters, and because the DRM probe has not
|
||||
// settled at startup.
|
||||
// Read seat0 fresh on every query: the values cached in `new()` go stale across a logout
|
||||
// or fast-user-switch, which would skip the greeter probe below and hand back the previous
|
||||
// session owner. Queried here and not in `new()` also because the read there hides greeters.
|
||||
let seat0_values = get_values_of_seat0(&[0, 2]);
|
||||
let seat0_username = seat0_values[1].clone();
|
||||
#[cfg(feature = "drm")]
|
||||
if self.seat0_username.is_empty() || is_gdm_user(&self.seat0_username) {
|
||||
if seat0_username.is_empty() || is_gdm_user(&seat0_username) {
|
||||
if let Some(username) = drm_login_screen_seat0_username() {
|
||||
return Some(username);
|
||||
}
|
||||
}
|
||||
if is_gdm_user(&self.seat0_username) && self.seat0_display_server == DISPLAY_SERVER_WAYLAND
|
||||
if seat0_username.is_empty() {
|
||||
None
|
||||
} else if is_gdm_user(&seat0_username)
|
||||
&& get_display_server_of_session(&seat0_values[0]) == DISPLAY_SERVER_WAYLAND
|
||||
{
|
||||
None
|
||||
} else if self.seat0_username.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(self.seat0_username.clone())
|
||||
Some(seat0_username)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -827,8 +827,9 @@ pub(crate) fn is_available_cached() -> bool {
|
||||
matches!(&*DRM_STATE.lock().unwrap(), ProbeState::Available(..))
|
||||
}
|
||||
|
||||
/// MAY BLOCK for seconds: never a routing gate.
|
||||
pub(super) fn is_available() -> bool {
|
||||
/// MAY BLOCK for seconds: never a routing gate. The one cross-module caller is the login-screen
|
||||
/// headless decision, where an unsettled "no" would start Xorg over a live Wayland greeter.
|
||||
pub(crate) fn is_available() -> bool {
|
||||
let verdict = {
|
||||
let mut st = DRM_STATE.lock().unwrap();
|
||||
if let ProbeState::Unavailable(since) = &*st {
|
||||
|
||||
Reference in New Issue
Block a user