mirror of
https://github.com/rustdesk/rustdesk.git
synced 2026-04-08 02:51:28 +03:00
Fix Windows session-based logon and lock-screen detection (#14620)
* Fix Windows session-based logon and lock-screen detection - scope LogonUI and locked-state checks to the current Windows session - allow permanent password fallback for logon and lock-screen access Signed-off-by: 21pages <sunboeasy@gmail.com> * Log permanent-password fallback on logon screen Signed-off-by: 21pages <sunboeasy@gmail.com> --------- Signed-off-by: 21pages <sunboeasy@gmail.com>
This commit is contained in:
@@ -580,9 +580,8 @@ extern "C"
|
|||||||
return rdp_or_console;
|
return rdp_or_console;
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOL is_session_locked(BOOL include_rdp)
|
BOOL is_session_locked(DWORD session_id)
|
||||||
{
|
{
|
||||||
DWORD session_id = get_current_session(include_rdp);
|
|
||||||
if (session_id == 0xFFFFFFFF) {
|
if (session_id == 0xFFFFFFFF) {
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -523,7 +523,7 @@ const SERVICE_TYPE: ServiceType = ServiceType::OWN_PROCESS;
|
|||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
fn get_current_session(rdp: BOOL) -> DWORD;
|
fn get_current_session(rdp: BOOL) -> DWORD;
|
||||||
fn is_session_locked(include_rdp: BOOL) -> BOOL;
|
fn is_session_locked(session_id: DWORD) -> BOOL;
|
||||||
fn LaunchProcessWin(
|
fn LaunchProcessWin(
|
||||||
cmd: *const u16,
|
cmd: *const u16,
|
||||||
session_id: DWORD,
|
session_id: DWORD,
|
||||||
@@ -1149,20 +1149,21 @@ pub fn is_prelogin() -> bool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_locked() -> bool {
|
pub fn is_locked() -> bool {
|
||||||
unsafe { is_session_locked(share_rdp()) == TRUE }
|
let Some(session_id) = get_current_process_session_id() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
unsafe { is_session_locked(session_id) == TRUE }
|
||||||
}
|
}
|
||||||
|
|
||||||
// `is_logon_ui()` is regardless of multiple sessions now.
|
|
||||||
// It only check if "LogonUI.exe" exists.
|
|
||||||
//
|
|
||||||
// If there're mulitple sessions (logged in users),
|
|
||||||
// some are in the login screen, while the others are not.
|
|
||||||
// Then this function may not work fine if the session we want to handle(connect) is not in the login screen.
|
|
||||||
// But it's a rare case and cannot be simply handled, so it will not be dealt with for the time being.
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_logon_ui() -> ResultType<bool> {
|
pub fn is_logon_ui() -> ResultType<bool> {
|
||||||
|
let Some(current_sid) = get_current_process_session_id() else {
|
||||||
|
return Ok(false);
|
||||||
|
};
|
||||||
let pids = get_pids("LogonUI.exe")?;
|
let pids = get_pids("LogonUI.exe")?;
|
||||||
Ok(!pids.is_empty())
|
Ok(pids
|
||||||
|
.into_iter()
|
||||||
|
.any(|pid| get_session_id_of_process(pid) == Some(current_sid)))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn is_root() -> bool {
|
pub fn is_root() -> bool {
|
||||||
|
|||||||
@@ -2025,7 +2025,7 @@ impl Connection {
|
|||||||
self.validate_password_plain(storage)
|
self.validate_password_plain(storage)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn validate_password(&mut self) -> bool {
|
fn validate_password(&mut self, allow_permanent_password: bool) -> bool {
|
||||||
if password::temporary_enabled() {
|
if password::temporary_enabled() {
|
||||||
let password = password::temporary_password();
|
let password = password::temporary_password();
|
||||||
if self.validate_one_password(&password) {
|
if self.validate_one_password(&password) {
|
||||||
@@ -2037,13 +2037,19 @@ impl Connection {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if password::permanent_enabled() {
|
if password::permanent_enabled() || allow_permanent_password {
|
||||||
|
let print_fallback = || {
|
||||||
|
if allow_permanent_password && !password::permanent_enabled() {
|
||||||
|
log::info!("Permanent password accepted via logon-screen fallback");
|
||||||
|
}
|
||||||
|
};
|
||||||
// Since hashed storage uses a prefix-based encoding, a hard plaintext that
|
// Since hashed storage uses a prefix-based encoding, a hard plaintext that
|
||||||
// happens to look like hashed storage could be mis-detected. Validate local storage
|
// happens to look like hashed storage could be mis-detected. Validate local storage
|
||||||
// and hard/preset plaintext via separate paths to avoid that ambiguity.
|
// and hard/preset plaintext via separate paths to avoid that ambiguity.
|
||||||
let (local_storage, _) = Config::get_local_permanent_password_storage_and_salt();
|
let (local_storage, _) = Config::get_local_permanent_password_storage_and_salt();
|
||||||
if !local_storage.is_empty() {
|
if !local_storage.is_empty() {
|
||||||
if self.validate_password_storage(&local_storage) {
|
if self.validate_password_storage(&local_storage) {
|
||||||
|
print_fallback();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -2054,6 +2060,7 @@ impl Connection {
|
|||||||
.cloned()
|
.cloned()
|
||||||
.unwrap_or_default();
|
.unwrap_or_default();
|
||||||
if !hard.is_empty() && self.validate_password_plain(&hard) {
|
if !hard.is_empty() && self.validate_password_plain(&hard) {
|
||||||
|
print_fallback();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2349,6 +2356,10 @@ impl Connection {
|
|||||||
#[cfg(any(target_os = "android", target_os = "ios"))]
|
#[cfg(any(target_os = "android", target_os = "ios"))]
|
||||||
let is_logon = || crate::platform::is_prelogin();
|
let is_logon = || crate::platform::is_prelogin();
|
||||||
|
|
||||||
|
let allow_logon_screen_password =
|
||||||
|
crate::get_builtin_option(keys::OPTION_ALLOW_LOGON_SCREEN_PASSWORD) == "Y"
|
||||||
|
&& is_logon();
|
||||||
|
|
||||||
if !hbb_common::is_ip_str(&lr.username)
|
if !hbb_common::is_ip_str(&lr.username)
|
||||||
&& !hbb_common::is_domain_port_str(&lr.username)
|
&& !hbb_common::is_domain_port_str(&lr.username)
|
||||||
&& lr.username != Config::get_id()
|
&& lr.username != Config::get_id()
|
||||||
@@ -2357,8 +2368,7 @@ impl Connection {
|
|||||||
.await;
|
.await;
|
||||||
return false;
|
return false;
|
||||||
} else if (password::approve_mode() == ApproveMode::Click
|
} else if (password::approve_mode() == ApproveMode::Click
|
||||||
&& !(crate::get_builtin_option(keys::OPTION_ALLOW_LOGON_SCREEN_PASSWORD) == "Y"
|
&& !allow_logon_screen_password)
|
||||||
&& is_logon()))
|
|
||||||
|| password::approve_mode() == ApproveMode::Both && !password::has_valid_password()
|
|| password::approve_mode() == ApproveMode::Both && !password::has_valid_password()
|
||||||
{
|
{
|
||||||
self.try_start_cm(lr.my_id, lr.my_name, false);
|
self.try_start_cm(lr.my_id, lr.my_name, false);
|
||||||
@@ -2394,7 +2404,7 @@ impl Connection {
|
|||||||
if !res {
|
if !res {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if !self.validate_password() {
|
if !self.validate_password(allow_logon_screen_password) {
|
||||||
self.update_failure(failure, false, 0);
|
self.update_failure(failure, false, 0);
|
||||||
if err_msg.is_empty() {
|
if err_msg.is_empty() {
|
||||||
self.send_login_error(crate::client::LOGIN_MSG_PASSWORD_WRONG)
|
self.send_login_error(crate::client::LOGIN_MSG_PASSWORD_WRONG)
|
||||||
|
|||||||
Reference in New Issue
Block a user