diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs index 7bdd322d3..19730e630 100644 --- a/libs/hbb_common/src/config.rs +++ b/libs/hbb_common/src/config.rs @@ -32,6 +32,10 @@ pub const COMPRESS_LEVEL: i32 = 3; const SERIAL: i32 = 3; const PASSWORD_ENC_VERSION: &str = "00"; +// config2 options +#[cfg(all(target_os = "linux"))] +pub const CONFIG_OPTION_ALLOW_LINUX_HEADLESS: &str = "allow-linux-headless"; + #[cfg(target_os = "macos")] lazy_static::lazy_static! { pub static ref ORG: Arc> = Arc::new(RwLock::new("com.carriez".to_owned())); diff --git a/src/platform/linux.rs b/src/platform/linux.rs index 9c5a8b9fc..e254af12e 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -9,6 +9,9 @@ use hbb_common::{ message_proto::Resolution, regex::{Captures, Regex}, }; +#[cfg(all(feature = "linux_headless"))] +#[cfg(not(any(feature = "flatpak", feature = "appimage")))] +use hbb_common::config::CONFIG_OPTION_ALLOW_LINUX_HEADLESS; use std::{ cell::RefCell, io::Write, @@ -69,6 +72,13 @@ pub struct xcb_xfixes_get_cursor_image { pub pixels: *const c_long, } +#[inline] +#[cfg(feature = "linux_headless")] +#[cfg(not(any(feature = "flatpak", feature = "appimage")))] +pub fn is_headless_allowed() -> bool { + Config::get_option(CONFIG_OPTION_ALLOW_LINUX_HEADLESS) == "Y" +} + #[inline] fn sleep_millis(millis: u64) { std::thread::sleep(Duration::from_millis(millis)); diff --git a/src/platform/linux_desktop_manager.rs b/src/platform/linux_desktop_manager.rs index fe60964cc..1382fa2ed 100644 --- a/src/platform/linux_desktop_manager.rs +++ b/src/platform/linux_desktop_manager.rs @@ -109,6 +109,10 @@ pub fn try_start_desktop(_username: &str, _passsword: &str) -> String { // No need to verify password here. return "".to_owned(); } + if username.is_empty() { + // Another user is logged in. No need to start a new xsession. + return "".to_owned(); + } if let Some(msg) = detect_headless() { return msg.to_owned(); diff --git a/src/rendezvous_mediator.rs b/src/rendezvous_mediator.rs index 3e3b6c9b3..97a6d91d8 100644 --- a/src/rendezvous_mediator.rs +++ b/src/rendezvous_mediator.rs @@ -75,7 +75,9 @@ impl RendezvousMediator { } #[cfg(all(target_os = "linux", feature = "linux_headless"))] #[cfg(not(any(feature = "flatpak", feature = "appimage")))] - crate::platform::linux_desktop_manager::start_xdesktop(); + if crate::platform::is_headless_allowed() { + crate::platform::linux_desktop_manager::start_xdesktop(); + } loop { Config::reset_online(); if Config::get_option("stop-service").is_empty() { diff --git a/src/server/connection.rs b/src/server/connection.rs index ed51a6c29..efa0f88e1 100644 --- a/src/server/connection.rs +++ b/src/server/connection.rs @@ -985,8 +985,10 @@ impl Connection { } #[cfg(feature = "linux_headless")] #[cfg(not(any(feature = "flatpak", feature = "appimage")))] - if linux_desktop_manager::is_headless() { - platform_additions.insert("headless".into(), json!(true)); + if crate::platform::is_headless_allowed() { + if linux_desktop_manager::is_headless() { + platform_additions.insert("headless".into(), json!(true)); + } } if !platform_additions.is_empty() { pi.platform_additions = @@ -1375,23 +1377,42 @@ impl Connection { #[cfg(all(target_os = "linux", feature = "linux_headless"))] #[cfg(not(any(feature = "flatpak", feature = "appimage")))] - let desktop_err = match lr.os_login.as_ref() { - Some(os_login) => { - linux_desktop_manager::try_start_desktop(&os_login.username, &os_login.password) + let is_headless_allowed = crate::platform::is_headless_allowed(); + #[cfg(all(target_os = "linux", feature = "linux_headless"))] + #[cfg(not(any(feature = "flatpak", feature = "appimage")))] + let desktop_err = if is_headless_allowed { + match lr.os_login.as_ref() { + Some(os_login) => linux_desktop_manager::try_start_desktop( + &os_login.username, + &os_login.password, + ), + None => linux_desktop_manager::try_start_desktop("", ""), } - None => linux_desktop_manager::try_start_desktop("", ""), + } else { + "".to_string() }; #[cfg(all(target_os = "linux", feature = "linux_headless"))] #[cfg(not(any(feature = "flatpak", feature = "appimage")))] - let is_headless = linux_desktop_manager::is_headless(); + let is_headless = is_headless_allowed && linux_desktop_manager::is_headless(); #[cfg(all(target_os = "linux", feature = "linux_headless"))] #[cfg(not(any(feature = "flatpak", feature = "appimage")))] let wait_ipc_timeout = 10_000; + #[cfg(all(target_os = "linux", feature = "linux_headless"))] + #[cfg(not(any(feature = "flatpak", feature = "appimage")))] + let is_headless_proc = is_headless_allowed; + #[cfg(any( + feature = "flatpak", + feature = "appimage", + not(all(target_os = "linux", feature = "linux_headless")) + ))] + let is_headless_proc = false; + // If err is LOGIN_MSG_DESKTOP_SESSION_NOT_READY, just keep this msg and go on checking password. #[cfg(all(target_os = "linux", feature = "linux_headless"))] #[cfg(not(any(feature = "flatpak", feature = "appimage")))] - if !desktop_err.is_empty() + if is_headless_proc + && !desktop_err.is_empty() && desktop_err != crate::client::LOGIN_MSG_DESKTOP_SESSION_NOT_READY { self.send_login_error(desktop_err).await; @@ -1424,22 +1445,23 @@ impl Connection { } else if self.is_recent_session() { #[cfg(all(target_os = "linux", feature = "linux_headless"))] #[cfg(not(any(feature = "flatpak", feature = "appimage")))] - if desktop_err.is_empty() { - #[cfg(target_os = "linux")] - if is_headless { - self.tx_desktop_ready.send(()).await.ok(); - let _res = timeout(wait_ipc_timeout, self.rx_cm_stream_ready.recv()).await; + if is_headless_proc { + if desktop_err.is_empty() { + if is_headless { + self.tx_desktop_ready.send(()).await.ok(); + let _res = + timeout(wait_ipc_timeout, self.rx_cm_stream_ready.recv()).await; + } + self.try_start_cm(lr.my_id.clone(), lr.my_name.clone(), true); + self.send_logon_response().await; + if self.port_forward_socket.is_some() { + return false; + } + } else { + self.send_login_error(desktop_err).await; } - self.try_start_cm(lr.my_id, lr.my_name, true); - self.send_logon_response().await; - if self.port_forward_socket.is_some() { - return false; - } - } else { - self.send_login_error(desktop_err).await; } - #[cfg(not(all(target_os = "linux", feature = "linux_headless")))] - { + if !is_headless_proc { self.try_start_cm(lr.my_id, lr.my_name, true); self.send_logon_response().await; if self.port_forward_socket.is_some() { @@ -1449,16 +1471,19 @@ impl Connection { } else if lr.password.is_empty() { #[cfg(all(target_os = "linux", feature = "linux_headless"))] #[cfg(not(any(feature = "flatpak", feature = "appimage")))] - if desktop_err.is_empty() { - self.try_start_cm(lr.my_id, lr.my_name, false); - } else { - self.send_login_error( - crate::client::LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_EMPTY, - ) - .await; + if is_headless_proc { + if desktop_err.is_empty() { + self.try_start_cm(lr.my_id.clone(), lr.my_name.clone(), false); + } else { + self.send_login_error( + crate::client::LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_EMPTY, + ) + .await; + } + } + if !is_headless_proc { + self.try_start_cm(lr.my_id, lr.my_name, false); } - #[cfg(not(all(target_os = "linux", feature = "linux_headless")))] - self.try_start_cm(lr.my_id, lr.my_name, false); } else { let mut failure = LOGIN_FAILURES .lock() @@ -1499,18 +1524,19 @@ impl Connection { .insert(self.ip.clone(), failure); #[cfg(all(target_os = "linux", feature = "linux_headless"))] #[cfg(not(any(feature = "flatpak", feature = "appimage")))] - if desktop_err.is_empty() { - self.send_login_error(crate::client::LOGIN_MSG_PASSWORD_WRONG) + if is_headless_proc { + if desktop_err.is_empty() { + self.send_login_error(crate::client::LOGIN_MSG_PASSWORD_WRONG) + .await; + self.try_start_cm(lr.my_id.clone(), lr.my_name.clone(), false); + } else { + self.send_login_error( + crate::client::LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_WRONG, + ) .await; - self.try_start_cm(lr.my_id, lr.my_name, false); - } else { - self.send_login_error( - crate::client::LOGIN_MSG_DESKTOP_SESSION_NOT_READY_PASSWORD_WRONG, - ) - .await; + } } - #[cfg(not(all(target_os = "linux", feature = "linux_headless")))] - { + if !is_headless_proc { self.send_login_error(crate::client::LOGIN_MSG_PASSWORD_WRONG) .await; self.try_start_cm(lr.my_id, lr.my_name, false); @@ -1521,23 +1547,23 @@ impl Connection { } #[cfg(all(target_os = "linux", feature = "linux_headless"))] #[cfg(not(any(feature = "flatpak", feature = "appimage")))] - if desktop_err.is_empty() { - #[cfg(target_os = "linux")] - if is_headless { - self.tx_desktop_ready.send(()).await.ok(); - let _res = - timeout(wait_ipc_timeout, self.rx_cm_stream_ready.recv()).await; + if is_headless_proc { + if desktop_err.is_empty() { + if is_headless { + self.tx_desktop_ready.send(()).await.ok(); + let _res = + timeout(wait_ipc_timeout, self.rx_cm_stream_ready.recv()).await; + } + self.send_logon_response().await; + self.try_start_cm(lr.my_id.clone(), lr.my_name.clone(), true); + if self.port_forward_socket.is_some() { + return false; + } + } else { + self.send_login_error(desktop_err).await; } - self.send_logon_response().await; - self.try_start_cm(lr.my_id, lr.my_name, true); - if self.port_forward_socket.is_some() { - return false; - } - } else { - self.send_login_error(desktop_err).await; } - #[cfg(not(all(target_os = "linux", feature = "linux_headless")))] - { + if !is_headless_proc { self.send_logon_response().await; self.try_start_cm(lr.my_id, lr.my_name, true); if self.port_forward_socket.is_some() { @@ -2361,19 +2387,16 @@ async fn start_ipc( args.push("--hide"); }; - #[cfg(target_os = "linux")] - #[cfg(not(feature = "linux_headless"))] - let user = None; - #[cfg(all(target_os = "linux", feature = "linux_headless"))] - #[cfg(any(feature = "flatpak", feature = "appimage"))] + #[cfg(any(feature = "flatpak", feature = "appimage", not(all(target_os = "linux", feature = "linux_headless"))))] let user = None; #[cfg(all(target_os = "linux", feature = "linux_headless"))] #[cfg(not(any(feature = "flatpak", feature = "appimage")))] let mut user = None; + // Cm run as user, wait until desktop session is ready. #[cfg(all(target_os = "linux", feature = "linux_headless"))] #[cfg(not(any(feature = "flatpak", feature = "appimage")))] - if linux_desktop_manager::is_headless() { + if crate::platform::is_headless_allowed() && linux_desktop_manager::is_headless() { let mut username = linux_desktop_manager::get_username(); loop { if !username.is_empty() {