Skip to content

Commit f02cd9c

Browse files
authored
Fix Windows session-based logon and lock-screen detection (rustdesk#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>
1 parent 1705165 commit f02cd9c

File tree

3 files changed

+27
-17
lines changed

3 files changed

+27
-17
lines changed

src/platform/windows.cc

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -580,9 +580,8 @@ extern "C"
580580
return rdp_or_console;
581581
}
582582

583-
BOOL is_session_locked(BOOL include_rdp)
583+
BOOL is_session_locked(DWORD session_id)
584584
{
585-
DWORD session_id = get_current_session(include_rdp);
586585
if (session_id == 0xFFFFFFFF) {
587586
return FALSE;
588587
}

src/platform/windows.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ const SERVICE_TYPE: ServiceType = ServiceType::OWN_PROCESS;
523523

524524
extern "C" {
525525
fn get_current_session(rdp: BOOL) -> DWORD;
526-
fn is_session_locked(include_rdp: BOOL) -> BOOL;
526+
fn is_session_locked(session_id: DWORD) -> BOOL;
527527
fn LaunchProcessWin(
528528
cmd: *const u16,
529529
session_id: DWORD,
@@ -1149,20 +1149,21 @@ pub fn is_prelogin() -> bool {
11491149
}
11501150

11511151
pub fn is_locked() -> bool {
1152-
unsafe { is_session_locked(share_rdp()) == TRUE }
1152+
let Some(session_id) = get_current_process_session_id() else {
1153+
return false;
1154+
};
1155+
unsafe { is_session_locked(session_id) == TRUE }
11531156
}
11541157

1155-
// `is_logon_ui()` is regardless of multiple sessions now.
1156-
// It only check if "LogonUI.exe" exists.
1157-
//
1158-
// If there're mulitple sessions (logged in users),
1159-
// some are in the login screen, while the others are not.
1160-
// Then this function may not work fine if the session we want to handle(connect) is not in the login screen.
1161-
// But it's a rare case and cannot be simply handled, so it will not be dealt with for the time being.
11621158
#[inline]
11631159
pub fn is_logon_ui() -> ResultType<bool> {
1160+
let Some(current_sid) = get_current_process_session_id() else {
1161+
return Ok(false);
1162+
};
11641163
let pids = get_pids("LogonUI.exe")?;
1165-
Ok(!pids.is_empty())
1164+
Ok(pids
1165+
.into_iter()
1166+
.any(|pid| get_session_id_of_process(pid) == Some(current_sid)))
11661167
}
11671168

11681169
pub fn is_root() -> bool {

src/server/connection.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2025,7 +2025,7 @@ impl Connection {
20252025
self.validate_password_plain(storage)
20262026
}
20272027

2028-
fn validate_password(&mut self) -> bool {
2028+
fn validate_password(&mut self, allow_permanent_password: bool) -> bool {
20292029
if password::temporary_enabled() {
20302030
let password = password::temporary_password();
20312031
if self.validate_one_password(&password) {
@@ -2037,13 +2037,19 @@ impl Connection {
20372037
return true;
20382038
}
20392039
}
2040-
if password::permanent_enabled() {
2040+
if password::permanent_enabled() || allow_permanent_password {
2041+
let print_fallback = || {
2042+
if allow_permanent_password && !password::permanent_enabled() {
2043+
log::info!("Permanent password accepted via logon-screen fallback");
2044+
}
2045+
};
20412046
// Since hashed storage uses a prefix-based encoding, a hard plaintext that
20422047
// happens to look like hashed storage could be mis-detected. Validate local storage
20432048
// and hard/preset plaintext via separate paths to avoid that ambiguity.
20442049
let (local_storage, _) = Config::get_local_permanent_password_storage_and_salt();
20452050
if !local_storage.is_empty() {
20462051
if self.validate_password_storage(&local_storage) {
2052+
print_fallback();
20472053
return true;
20482054
}
20492055
} else {
@@ -2054,6 +2060,7 @@ impl Connection {
20542060
.cloned()
20552061
.unwrap_or_default();
20562062
if !hard.is_empty() && self.validate_password_plain(&hard) {
2063+
print_fallback();
20572064
return true;
20582065
}
20592066
}
@@ -2349,6 +2356,10 @@ impl Connection {
23492356
#[cfg(any(target_os = "android", target_os = "ios"))]
23502357
let is_logon = || crate::platform::is_prelogin();
23512358

2359+
let allow_logon_screen_password =
2360+
crate::get_builtin_option(keys::OPTION_ALLOW_LOGON_SCREEN_PASSWORD) == "Y"
2361+
&& is_logon();
2362+
23522363
if !hbb_common::is_ip_str(&lr.username)
23532364
&& !hbb_common::is_domain_port_str(&lr.username)
23542365
&& lr.username != Config::get_id()
@@ -2357,8 +2368,7 @@ impl Connection {
23572368
.await;
23582369
return false;
23592370
} else if (password::approve_mode() == ApproveMode::Click
2360-
&& !(crate::get_builtin_option(keys::OPTION_ALLOW_LOGON_SCREEN_PASSWORD) == "Y"
2361-
&& is_logon()))
2371+
&& !allow_logon_screen_password)
23622372
|| password::approve_mode() == ApproveMode::Both && !password::has_valid_password()
23632373
{
23642374
self.try_start_cm(lr.my_id, lr.my_name, false);
@@ -2394,7 +2404,7 @@ impl Connection {
23942404
if !res {
23952405
return true;
23962406
}
2397-
if !self.validate_password() {
2407+
if !self.validate_password(allow_logon_screen_password) {
23982408
self.update_failure(failure, false, 0);
23992409
if err_msg.is_empty() {
24002410
self.send_login_error(crate::client::LOGIN_MSG_PASSWORD_WRONG)

0 commit comments

Comments
 (0)