ohmu
·
2026-10-15
1#include "users.h"
2#include "common/debug.h"
3#include "common/windows/unicode.h"
4#include "common/time.h"
5
6#include <windows.h>
7#include <wtsapi32.h>
8#include <ws2tcpip.h>
9
10const char* ffDetectUsers(FFUsersOptions* options, FFlist* users) {
11 WTS_SESSION_INFO_1W* sessionInfo;
12 DWORD sessionCount;
13 DWORD level = 1;
14
15 if (!WTSEnumerateSessionsExW(WTS_CURRENT_SERVER_HANDLE, &level, 0, &sessionInfo, &sessionCount)) {
16 FF_DEBUG("WTSEnumerateSessionsExW() failed: %s", ffDebugWin32Error(GetLastError()));
17 return "WTSEnumerateSessionsW(WTS_CURRENT_SERVER_HANDLE) failed";
18 }
19
20 for (DWORD i = 0; i < sessionCount; i++) {
21 WTS_SESSION_INFO_1W* session = &sessionInfo[i];
22 if (session->State != WTSActive) {
23 continue;
24 }
25
26 FF_STRBUF_AUTO_DESTROY userName = ffStrbufCreateWS(session->pUserName);
27
28 if (options->myselfOnly && !ffStrbufEqual(&instance.state.platform.userName, &userName)) {
29 continue;
30 }
31
32 FFUserResult* user = FF_LIST_ADD(FFUserResult, *users);
33 ffStrbufInitMove(&user->name, &userName);
34 ffStrbufInitWS(&user->hostName, session->pHostName);
35 ffStrbufInitWS(&user->sessionName, session->pSessionName);
36 ffStrbufInit(&user->clientIp);
37 user->loginTime = 0;
38
39 DWORD bytes = 0;
40 PWTS_CLIENT_ADDRESS address = nullptr;
41 if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSClientAddress, (LPWSTR*) &address, &bytes)) {
42 if (address->AddressFamily == AF_INET) {
43 ffStrbufSetF(&user->clientIp, "%u.%u.%u.%u", address->Address[2], address->Address[3], address->Address[4], address->Address[5]);
44 } else if (address->AddressFamily == AF_INET6) {
45 char ipStr[INET6_ADDRSTRLEN];
46 const char* end = RtlIpv6AddressToStringA((const IN6_ADDR*) address->Address, ipStr);
47 ffStrbufSetNS(&user->clientIp, (uint32_t) (end - ipStr), ipStr);
48 }
49 WTSFreeMemory(address);
50 }
51
52 bytes = 0;
53 PWTSINFOW wtsInfo = nullptr;
54 if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session->SessionId, WTSSessionInfo, (LPWSTR*) &wtsInfo, &bytes)) {
55 user->loginTime = ffFileTimeToUnixMs((uint64_t) wtsInfo->LogonTime.QuadPart);
56 WTSFreeMemory(wtsInfo);
57 }
58 }
59
60 WTSFreeMemoryExW(WTSTypeSessionInfoLevel1, sessionInfo, 1);
61
62 return nullptr;
63}