From b2b04efee2223828b8aa7a90cdf34cff9a7a2b5a Mon Sep 17 00:00:00 2001 From: FrankHan Date: Sun, 26 Jul 2026 12:58:13 +0800 Subject: [PATCH 1/3] fix(ohos): isolate mobile config and platform paths --- src/config.rs | 51 ++++++++++++++++++++++++++++----------------- src/fingerprint.rs | 4 ++-- src/lib.rs | 14 ++++++------- src/platform/mod.rs | 4 ++-- 4 files changed, 43 insertions(+), 30 deletions(-) diff --git a/src/config.rs b/src/config.rs index 707bbe0f7d..c876362077 100644 --- a/src/config.rs +++ b/src/config.rs @@ -92,7 +92,7 @@ lazy_static::lazy_static! { pub static ref APP_DIR: RwLock = Default::default(); } -#[cfg(any(target_os = "android", target_os = "ios"))] +#[cfg(any(target_os = "android", target_os = "ios", target_env = "ohos"))] lazy_static::lazy_static! { pub static ref APP_HOME_DIR: RwLock = Default::default(); } @@ -137,7 +137,10 @@ pub fn is_service_ipc_postfix(postfix: &str) -> bool { // Keep Linux/macOS IPC parent directory rules in one place to avoid drift between // `ipc_path()` and Unix `ipc_path_for_uid()`. -#[cfg(any(target_os = "linux", target_os = "macos"))] +#[cfg(any( + all(target_os = "linux", not(target_env = "ohos")), + target_os = "macos" +))] #[inline] fn ipc_parent_dir_for_uid(uid: u32, postfix: &str) -> String { let app_name = APP_NAME.read().unwrap().clone(); @@ -459,7 +462,7 @@ pub fn get_online_state() -> i64 { *ONLINE.lock().unwrap().values().max().unwrap_or(&0) } -#[cfg(not(any(target_os = "android", target_os = "ios")))] +#[cfg(not(any(target_os = "android", target_os = "ios", target_env = "ohos")))] fn patch(path: PathBuf) -> PathBuf { if let Some(_tmp) = path.to_str() { #[cfg(windows)] @@ -471,7 +474,7 @@ fn patch(path: PathBuf) -> PathBuf { .into(); #[cfg(target_os = "macos")] return _tmp.replace("Application Support", "Preferences").into(); - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] { if _tmp == "/root" { if let Ok(user) = crate::platform::linux::run_cmds_trim_newline("whoami") { @@ -766,9 +769,9 @@ impl Config { /// where an attacker can manipulate the environment variable to inject malicious /// paths into privileged operations. pub fn get_home() -> PathBuf { - #[cfg(any(target_os = "android", target_os = "ios"))] + #[cfg(any(target_os = "android", target_os = "ios", target_env = "ohos"))] return PathBuf::from(APP_HOME_DIR.read().unwrap().as_str()); - #[cfg(not(any(target_os = "android", target_os = "ios")))] + #[cfg(not(any(target_os = "android", target_os = "ios", target_env = "ohos")))] { if let Some(path) = dirs_next::home_dir() { patch(path) @@ -781,13 +784,13 @@ impl Config { } pub fn path>(p: P) -> PathBuf { - #[cfg(any(target_os = "android", target_os = "ios"))] + #[cfg(any(target_os = "android", target_os = "ios", target_env = "ohos"))] { let mut path: PathBuf = APP_DIR.read().unwrap().clone().into(); path.push(p); return path; } - #[cfg(not(any(target_os = "android", target_os = "ios")))] + #[cfg(not(any(target_os = "android", target_os = "ios", target_env = "ohos")))] { #[cfg(not(target_os = "macos"))] let org = "".to_owned(); @@ -820,7 +823,7 @@ impl Config { return path.clone(); } } - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] { let mut path = Self::get_home(); path.push(format!(".local/share/logs/{}", *APP_NAME.read().unwrap())); @@ -856,23 +859,30 @@ impl Config { } #[cfg(not(windows))] { - #[cfg(target_os = "android")] + #[cfg(any(target_os = "android", target_env = "ohos"))] use std::os::unix::fs::PermissionsExt; - #[cfg(target_os = "android")] + #[cfg(any(target_os = "android", target_env = "ohos"))] let mut path: PathBuf = format!("{}/{}", *APP_DIR.read().unwrap(), *APP_NAME.read().unwrap()).into(); - #[cfg(any(target_os = "linux", target_os = "macos"))] + #[cfg(any( + all(target_os = "linux", not(target_env = "ohos")), + target_os = "macos" + ))] let mut path: PathBuf = { let uid = unsafe { libc::geteuid() as u32 }; ipc_parent_dir_for_uid(uid, postfix).into() }; - #[cfg(not(any(target_os = "android", target_os = "linux", target_os = "macos")))] + #[cfg(not(any( + target_os = "android", + all(target_os = "linux", not(target_env = "ohos")), + target_os = "macos" + )))] let mut path: PathBuf = format!("/tmp/{}", *APP_NAME.read().unwrap()).into(); // Android stores IPC sockets under app-controlled directories. Create the IPC parent // dir and enforce the expected mode here. On other Unix platforms, `ipc_path()` is // intentionally side-effect free (no mkdir/chmod); callers should enforce directory and // socket permissions at the IPC server boundary. - #[cfg(target_os = "android")] + #[cfg(any(target_os = "android", target_env = "ohos"))] { fs::create_dir_all(&path).ok(); let path_mode = if is_service_ipc_postfix(postfix) { @@ -887,7 +897,10 @@ impl Config { } } - #[cfg(any(target_os = "linux", target_os = "macos"))] + #[cfg(any( + all(target_os = "linux", not(target_env = "ohos")), + target_os = "macos" + ))] pub fn ipc_path_for_uid(uid: u32, postfix: &str) -> String { let parent = ipc_parent_dir_for_uid(uid, postfix); format!("{parent}/ipc{postfix}") @@ -1020,12 +1033,12 @@ impl Config { std::cmp::max(CONFIG2.read().unwrap().serial, SERIAL) } - #[cfg(any(target_os = "android", target_os = "ios"))] + #[cfg(any(target_os = "android", target_os = "ios", target_env = "ohos"))] fn gen_id() -> Option { Self::get_auto_id() } - #[cfg(not(any(target_os = "android", target_os = "ios")))] + #[cfg(not(any(target_os = "android", target_os = "ios", target_env = "ohos")))] fn gen_id() -> Option { let hostname_as_id = BUILTIN_SETTINGS .read() @@ -1047,7 +1060,7 @@ impl Config { } fn get_auto_id() -> Option { - #[cfg(any(target_os = "android", target_os = "ios"))] + #[cfg(any(target_os = "android", target_os = "ios", target_env = "ohos"))] { return Some( rand::thread_rng() @@ -1056,7 +1069,7 @@ impl Config { ); } - #[cfg(not(any(target_os = "android", target_os = "ios")))] + #[cfg(not(any(target_os = "android", target_os = "ios", target_env = "ohos")))] { let mut id = 0u32; if let Ok(Some(ma)) = mac_address::get_mac_address() { diff --git a/src/fingerprint.rs b/src/fingerprint.rs index 2d8985e38a..c2a5f600d2 100644 --- a/src/fingerprint.rs +++ b/src/fingerprint.rs @@ -223,9 +223,9 @@ impl FingerprintingInfo { platform: std::env::consts::OS.to_string(), arch: std::env::consts::ARCH.to_string(), id, - #[cfg(any(target_os = "android", target_os = "ios"))] + #[cfg(any(target_os = "android", target_os = "ios", target_env = "ohos"))] addr: "0".repeat(16), - #[cfg(not(any(target_os = "android", target_os = "ios")))] + #[cfg(not(any(target_os = "android", target_os = "ios", target_env = "ohos")))] addr: { let mut addr = default_net::get_mac().map(|m| m.addr).unwrap_or_default(); if addr.is_empty() { diff --git a/src/lib.rs b/src/lib.rs index 2b35642190..b5e8d18bbf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -30,7 +30,7 @@ pub mod config; pub mod fs; pub mod mem; pub use lazy_static; -#[cfg(not(any(target_os = "android", target_os = "ios")))] +#[cfg(not(any(target_os = "android", target_os = "ios", target_env = "ohos")))] pub use mac_address; pub use rand; pub use regex; @@ -44,9 +44,9 @@ pub use directories_next; pub use libc; pub mod keyboard; pub use base64; -#[cfg(not(any(target_os = "android", target_os = "ios")))] +#[cfg(not(any(target_os = "android", target_os = "ios", target_env = "ohos")))] pub use dlopen; -#[cfg(not(any(target_os = "android", target_os = "ios")))] +#[cfg(not(any(target_os = "android", target_os = "ios", target_env = "ohos")))] pub use machine_uid; pub use serde_derive; pub use serde_json; @@ -61,17 +61,17 @@ pub mod stream; pub mod websocket; #[cfg(feature = "webrtc")] pub mod webrtc; -#[cfg(any(target_os = "android", target_os = "ios"))] +#[cfg(any(target_os = "android", target_os = "ios", target_env = "ohos"))] pub use rustls_platform_verifier; pub use stream::Stream; pub use whoami; pub mod tls; pub mod verifier; pub use async_recursion; -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(target_env = "ohos")))] pub use users; pub use libloading; -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(target_env = "ohos")))] pub use x11; pub type SessionID = uuid::Uuid; @@ -316,7 +316,7 @@ pub fn get_exe_time() -> SystemTime { /// - Windows shutdown: "The media is write protected. (os error 19)" /// - macOS (hard to reproduce, reproduced at login screen): "No matching IOPlatformUUID in `ioreg -rd1 -c IOPlatformExpertDevice` command" pub fn get_uuid() -> Vec { - #[cfg(not(any(target_os = "android", target_os = "ios")))] + #[cfg(not(any(target_os = "android", target_os = "ios", target_env = "ohos")))] { use std::sync::atomic::{AtomicUsize, Ordering}; diff --git a/src/platform/mod.rs b/src/platform/mod.rs index 6818add407..76fcbbc467 100644 --- a/src/platform/mod.rs +++ b/src/platform/mod.rs @@ -1,4 +1,4 @@ -#[cfg(target_os = "linux")] +#[cfg(all(target_os = "linux", not(target_env = "ohos")))] pub mod linux; #[cfg(target_os = "macos")] @@ -53,7 +53,7 @@ extern "C" fn breakdown_signal_handler(sig: i32) { stack.join("\n").to_string() ); if !info.is_empty() { - #[cfg(target_os = "linux")] + #[cfg(all(target_os = "linux", not(target_env = "ohos")))] linux::system_message( "RustDesk", &format!("Got signal {} and exit.{}", sig, info), From c30d8179050cbaec4d2cf343a253833c2d6a68bc Mon Sep 17 00:00:00 2001 From: FrankHan Date: Sun, 26 Jul 2026 12:58:13 +0800 Subject: [PATCH 2/3] fix(ohos): use rustls for websocket and proxy TLS --- Cargo.toml | 16 +++++++++++----- src/proxy.rs | 44 +++++++++++++++++++++++++++++++++++--------- src/tls.rs | 5 +++++ src/websocket.rs | 24 ++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 14 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 6ad3012fa9..08b86615d4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -57,9 +57,6 @@ tokio-rustls = { version = "0.26", features = [ "tls12", "ring", ], default-features = false } -tokio-native-tls = "0.3" -tokio-tungstenite = { version = "0.26", features = ["native-tls", "rustls-tls-native-roots", "rustls-tls-webpki-roots"] } -tungstenite = { version = "0.26", features = ["native-tls", "rustls-tls-native-roots", "rustls-tls-webpki-roots"] } rustls-platform-verifier = "0.6" rustls-pki-types = "1.11" rustls-native-certs = "0.8" @@ -68,7 +65,16 @@ async-recursion = "1.1" webrtc = { version = "0.14.0", optional = true } libloading = "0.8" -[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] +[target.'cfg(target_env = "ohos")'.dependencies] +tokio-tungstenite = { version = "0.26", features = ["rustls-tls-native-roots", "rustls-tls-webpki-roots"] } +tungstenite = { version = "0.26", features = ["rustls-tls-native-roots", "rustls-tls-webpki-roots"] } + +[target.'cfg(not(target_env = "ohos"))'.dependencies] +tokio-native-tls = "0.3" +tokio-tungstenite = { version = "0.26", features = ["native-tls", "rustls-tls-native-roots", "rustls-tls-webpki-roots"] } +tungstenite = { version = "0.26", features = ["native-tls", "rustls-tls-native-roots", "rustls-tls-webpki-roots"] } + +[target.'cfg(not(any(target_os = "android", target_os = "ios", target_env = "ohos")))'.dependencies] mac_address = "1.1" default_net = { git = "https://github.com/rustdesk-org/default_net" } machine-uid = { git = "https://github.com/rustdesk-org/machine-uid" } @@ -92,7 +98,7 @@ winapi = { version = "0.3", features = [ [target.'cfg(target_os = "macos")'.dependencies] osascript = "0.3" -[target.'cfg(target_os = "linux")'.dependencies] +[target.'cfg(all(target_os = "linux", not(target_env = "ohos")))'.dependencies] sctk = { package = "smithay-client-toolkit", version = "0.20.0", default-features = false, features = [ "calloop", ] } diff --git a/src/proxy.rs b/src/proxy.rs index d3b8a76d29..7964744d58 100644 --- a/src/proxy.rs +++ b/src/proxy.rs @@ -9,6 +9,7 @@ use base64::{engine::general_purpose, Engine}; use httparse::{Error as HttpParseError, Response, EMPTY_HEADER}; use thiserror::Error as ThisError; use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt, BufStream}; +#[cfg(not(target_env = "ohos"))] use tokio_native_tls::{native_tls, TlsConnector, TlsStream}; use tokio_rustls::{client::TlsStream as RustlsTlsStream, TlsConnector as RustlsTlsConnector}; use tokio_socks::{tcp::Socks5Stream, IntoTargetAddr, TargetAddr}; @@ -45,6 +46,7 @@ pub enum ProxyError { HttpCode200(u16), #[error("The proxy address resolution failed: {0}")] AddressResolutionFailed(String), + #[cfg(not(target_env = "ohos"))] #[error("The native tls error: {0}")] NativeTlsError(#[from] tokio_native_tls::native_tls::Error), } @@ -425,6 +427,7 @@ impl Proxy { ) .await? } + #[cfg(not(target_env = "ohos"))] TlsType::NativeTls => { self.https_connect_nativetls_wrap_danger( &url, @@ -435,6 +438,10 @@ impl Proxy { ) .await? } + #[cfg(target_env = "ohos")] + TlsType::NativeTls => { + bail!("NativeTls is unavailable on OpenHarmony") + } _ => { // Unreachable crate::bail!("Unreachable, TlsType::Plain in HTTPS proxy"); @@ -477,6 +484,7 @@ impl Proxy { }; } + #[cfg(not(target_env = "ohos"))] async fn https_connect_nativetls_wrap_danger<'a>( &self, url: &str, @@ -503,6 +511,7 @@ impl Proxy { Ok(DynTcpStream(Box::new(s))) } + #[cfg(not(target_env = "ohos"))] pub async fn https_connect_nativetls<'a, Input>( &self, io: Input, @@ -584,16 +593,33 @@ impl Proxy { ) .await? } else if !is_tls_type_cached { - log::warn!("Falling back to native-tls for HTTPS proxy server."); - self.https_connect_nativetls_wrap_danger( - &url, - local, - proxy, - &target_addr, - origin_danger_accept_invalid_cert, - ) - .await? + #[cfg(target_env = "ohos")] + { + log::error!( + "Failed to connect to HTTPS proxy server with rustls: {:?}.", + e + ); + bail!(e) + } + #[cfg(not(target_env = "ohos"))] + { + log::warn!("Falling back to native-tls for HTTPS proxy server."); + self.https_connect_nativetls_wrap_danger( + &url, + local, + proxy, + &target_addr, + origin_danger_accept_invalid_cert, + ) + .await? + } } else { + #[cfg(target_env = "ohos")] + log::error!( + "Failed to connect to HTTPS proxy server with rustls: {:?}.", + e + ); + #[cfg(not(target_env = "ohos"))] log::error!( "Failed to connect to HTTPS proxy server with native-tls: {:?}.", e diff --git a/src/tls.rs b/src/tls.rs index b0862369bc..f139daba48 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -40,6 +40,11 @@ fn get_domain_and_port_from_url(url: &str) -> &str { #[inline] pub fn upsert_tls_cache(url: &str, tls_type: TlsType, danger_accept_invalid_cert: bool) { + #[cfg(target_env = "ohos")] + if matches!(tls_type, TlsType::NativeTls) { + return; + } + if is_plain(url) { return; } diff --git a/src/websocket.rs b/src/websocket.rs index 7bf2108409..fdcb9d0bcb 100644 --- a/src/websocket.rs +++ b/src/websocket.rs @@ -20,6 +20,7 @@ use std::{ time::Duration, }; use tokio::{net::TcpStream, time::timeout}; +#[cfg(not(target_env = "ohos"))] use tokio_native_tls::native_tls::TlsConnector; use tokio_tungstenite::{ connect_async_tls_with_config, tungstenite::protocol::Message as WsMessage, Connector, @@ -43,12 +44,32 @@ impl WsFramedStream { ) -> ResultType> { match tls_type { TlsType::Plain => Ok(Some(Connector::Plain)), + #[cfg(not(target_env = "ohos"))] TlsType::NativeTls => { let connector = TlsConnector::builder() .danger_accept_invalid_certs(danger_accept_invalid_certs) .build()?; Ok(Some(Connector::NativeTls(connector))) } + #[cfg(target_env = "ohos")] + TlsType::NativeTls => { + bail!("NativeTls is unavailable on OpenHarmony") + } + #[cfg(target_env = "ohos")] + TlsType::Rustls => { + let connector = match crate::verifier::client_config(danger_accept_invalid_certs) { + Ok(client_config) => Some(Connector::Rustls(Arc::new(client_config))), + Err(e) => { + log::warn!( + "Failed to get client config: {:?}, fallback to default connector", + e + ); + None + } + }; + Ok(connector) + } + #[cfg(not(target_env = "ohos"))] TlsType::Rustls => { let connector = match crate::verifier::client_config(danger_accept_invalid_certs) { Ok(client_config) => Some(Connector::Rustls(Arc::new(client_config))), @@ -129,6 +150,7 @@ impl WsFramedStream { ) .await } + #[cfg(not(target_env = "ohos"))] (TlsType::Rustls, false, Some(_)) => { log::warn!( "WebSocket connection with rustls-tls failed, try native-tls: {}, {:?}", @@ -145,6 +167,7 @@ impl WsFramedStream { ) .await } + #[cfg(not(target_env = "ohos"))] (TlsType::NativeTls, _, None) => { log::warn!( "WebSocket connection with native-tls failed, try accept invalid certs: {}, {:?}", @@ -191,6 +214,7 @@ impl WsFramedStream { let stream = Self::connect(url.as_ref(), ms_timeout).await?; let addr = match stream.get_ref() { MaybeTlsStream::Plain(tcp) => tcp.peer_addr()?, + #[cfg(not(target_env = "ohos"))] MaybeTlsStream::NativeTls(tls) => tls.get_ref().get_ref().get_ref().peer_addr()?, MaybeTlsStream::Rustls(tls) => tls.get_ref().0.peer_addr()?, _ => return Err(Error::new(ErrorKind::Other, "Unsupported stream type").into()), From dfa8060f807991b6b4ede881b9fa5865b227d3f9 Mon Sep 17 00:00:00 2001 From: FrankHan Date: Sun, 26 Jul 2026 17:05:20 +0800 Subject: [PATCH 3/3] fix(ohos): preserve app-owned IPC path --- src/config.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/config.rs b/src/config.rs index c876362077..126f1b3184 100644 --- a/src/config.rs +++ b/src/config.rs @@ -874,6 +874,7 @@ impl Config { }; #[cfg(not(any( target_os = "android", + target_env = "ohos", all(target_os = "linux", not(target_env = "ohos")), target_os = "macos" )))]