diff --git a/src/platform/windows.cc b/src/platform/windows.cc index e3ef0944d..7ed76d2e4 100644 --- a/src/platform/windows.cc +++ b/src/platform/windows.cc @@ -10,6 +10,9 @@ #include #include #include +#include + +extern "C" uint32_t get_session_user_info(PWSTR bufin, uint32_t nin, uint32_t id); void flog(char const *fmt, ...) { @@ -23,6 +26,95 @@ void flog(char const *fmt, ...) fclose(h); } +static BOOL GetProcessUserName(DWORD processID, LPWSTR outUserName, DWORD inUserNameSize) +{ + BOOL ret = FALSE; + HANDLE hProcess = NULL; + HANDLE hToken = NULL; + PTOKEN_USER tokenUser = NULL; + wchar_t *userName = NULL; + wchar_t *domainName = NULL; + + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, processID); + if (hProcess == NULL) + { + goto cleanup; + } + if (!OpenProcessToken(hProcess, TOKEN_QUERY, &hToken)) + { + goto cleanup; + } + DWORD tokenInfoLength = 0; + GetTokenInformation(hToken, TokenUser, NULL, 0, &tokenInfoLength); + if (tokenInfoLength == 0) + { + goto cleanup; + } + tokenUser = (PTOKEN_USER)malloc(tokenInfoLength); + if (tokenUser == NULL) + { + goto cleanup; + } + if (!GetTokenInformation(hToken, TokenUser, tokenUser, tokenInfoLength, &tokenInfoLength)) + { + goto cleanup; + } + DWORD userSize = 0; + DWORD domainSize = 0; + SID_NAME_USE snu; + LookupAccountSidW(NULL, tokenUser->User.Sid, NULL, &userSize, NULL, &domainSize, &snu); + if (userSize == 0 || domainSize == 0) + { + goto cleanup; + } + userName = (wchar_t *)malloc((userSize + 1) * sizeof(wchar_t)); + if (userName == NULL) + { + goto cleanup; + } + domainName = (wchar_t *)malloc((domainSize + 1) * sizeof(wchar_t)); + if (domainName == NULL) + { + goto cleanup; + } + if (!LookupAccountSidW(NULL, tokenUser->User.Sid, userName, &userSize, domainName, &domainSize, &snu)) + { + goto cleanup; + } + userName[userSize] = L'\0'; + domainName[domainSize] = L'\0'; + if (inUserNameSize <= userSize) + { + goto cleanup; + } + wcscpy(outUserName, userName); + + ret = TRUE; +cleanup: + if (userName) + { + free(userName); + } + if (domainName) + { + free(domainName); + } + if (tokenUser != NULL) + { + free(tokenUser); + } + if (hToken != NULL) + { + CloseHandle(hToken); + } + if (hProcess != NULL) + { + CloseHandle(hProcess); + } + + return ret; +} + // ultravnc has rdp support // https://github.com/veyon/ultravnc/blob/master/winvnc/winvnc/service.cpp // https://github.com/TigerVNC/tigervnc/blob/master/win/winvnc/VNCServerService.cxx @@ -54,6 +146,54 @@ DWORD GetLogonPid(DWORD dwSessionId, BOOL as_user) return dwLogonPid; } +static DWORD GetFallbackUserPid(DWORD dwSessionId) +{ + DWORD dwFallbackPid = 0; + const wchar_t* fallbackUserProcs[] = {L"sihost.exe"}; + const int maxUsernameLen = 256; + wchar_t sessionUsername[maxUsernameLen + 1] = {0}; + wchar_t processUsername[maxUsernameLen + 1] = {0}; + + if (get_session_user_info(sessionUsername, maxUsernameLen, dwSessionId) == 0) + { + return 0; + } + HANDLE hSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); + if (hSnap != INVALID_HANDLE_VALUE) + { + PROCESSENTRY32W procEntry; + procEntry.dwSize = sizeof procEntry; + + if (Process32FirstW(hSnap, &procEntry)) + do + { + for (int i = 0; i < sizeof(fallbackUserProcs) / sizeof(fallbackUserProcs[0]); i++) + { + DWORD dwProcessSessionId = 0; + if (_wcsicmp(procEntry.szExeFile, fallbackUserProcs[i]) == 0 && + ProcessIdToSessionId(procEntry.th32ProcessID, &dwProcessSessionId) && + dwProcessSessionId == dwSessionId) + { + memset(processUsername, 0, sizeof(processUsername)); + if (GetProcessUserName(procEntry.th32ProcessID, processUsername, maxUsernameLen)) { + if (_wcsicmp(sessionUsername, processUsername) == 0) + { + dwFallbackPid = procEntry.th32ProcessID; + break; + } + } + } + } + if (dwFallbackPid != 0) + { + break; + } + } while (Process32NextW(hSnap, &procEntry)); + CloseHandle(hSnap); + } + return dwFallbackPid; +} + // START the app as system extern "C" { @@ -63,6 +203,10 @@ extern "C" { BOOL bResult = FALSE; DWORD Id = GetLogonPid(dwSessionId, as_user); + if (Id == 0) + { + Id = GetFallbackUserPid(dwSessionId); + } if (pDwTokenPid) *pDwTokenPid = Id; if (HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, Id)) @@ -436,7 +580,7 @@ extern "C" return nout; } - uint32_t get_session_user_info(PWSTR bufin, uint32_t nin, BOOL rdp, uint32_t id) + uint32_t get_session_user_info(PWSTR bufin, uint32_t nin, uint32_t id) { uint32_t nout = 0; PWSTR buf = NULL; diff --git a/src/platform/windows.rs b/src/platform/windows.rs index 617bfc8eb..c3cd5567f 100644 --- a/src/platform/windows.rs +++ b/src/platform/windows.rs @@ -825,12 +825,12 @@ fn get_current_session_username() -> Option { fn get_session_username(session_id: u32) -> String { extern "C" { - fn get_session_user_info(path: *mut u16, n: u32, rdp: bool, session_id: u32) -> u32; + fn get_session_user_info(path: *mut u16, n: u32, session_id: u32) -> u32; } let buff_size = 256; let mut buff: Vec = Vec::with_capacity(buff_size); buff.resize(buff_size, 0); - let n = unsafe { get_session_user_info(buff.as_mut_ptr(), buff_size as _, true, session_id) }; + let n = unsafe { get_session_user_info(buff.as_mut_ptr(), buff_size as _, session_id) }; if n == 0 { return "".to_owned(); }