diff --git a/src/os/win32/sigar_os.h b/src/os/win32/sigar_os.h index 3950a926..f9bf2e72 100644 --- a/src/os/win32/sigar_os.h +++ b/src/os/win32/sigar_os.h @@ -97,6 +97,84 @@ typedef struct _IP_ADAPTER_INFO { /* end iptypes.h */ +/* from wtsapi32.h not in vs6.0 */ +typedef enum { + WTSInitialProgram, + WTSApplicationName, + WTSWorkingDirectory, + WTSOEMId, + WTSSessionId, + WTSUserName, + WTSWinStationName, + WTSDomainName, + WTSConnectState, + WTSClientBuildNumber, + WTSClientName, + WTSClientDirectory, + WTSClientProductId, + WTSClientHardwareId, + WTSClientAddress, + WTSClientDisplay, + WTSClientProtocolType, +} WTS_INFO_CLASS; + +typedef enum _WTS_CONNECTSTATE_CLASS { + WTSActive, + WTSConnected, + WTSConnectQuery, + WTSShadow, + WTSDisconnected, + WTSIdle, + WTSListen, + WTSReset, + WTSDown, + WTSInit +} WTS_CONNECTSTATE_CLASS; + +#define WTS_PROTOCOL_TYPE_CONSOLE 0 +#define WTS_PROTOCOL_TYPE_ICA 1 +#define WTS_PROTOCOL_TYPE_RDP 2 + +typedef struct _WTS_SESSION_INFO { + DWORD SessionId; + LPTSTR pWinStationName; + DWORD State; +} WTS_SESSION_INFO, *PWTS_SESSION_INFO; + +typedef struct _WTS_PROCESS_INFO { + DWORD SessionId; + DWORD ProcessId; + LPSTR pProcessName; + PSID pUserSid; +} WTS_PROCESS_INFO, *PWTS_PROCESS_INFO; + +typedef struct _WTS_CLIENT_ADDRESS { + DWORD AddressFamily; + BYTE Address[20]; +} WTS_CLIENT_ADDRESS, *PWTS_CLIENT_ADDRESS; + +/* the WINSTATION_INFO stuff here is undocumented + * got the howto from google groups: + * http://redirx.com/?31gy + */ +typedef enum _WINSTATION_INFO_CLASS { + WinStationInformation = 8 +} WINSTATION_INFO_CLASS; + +typedef struct _WINSTATION_INFO { + BYTE Reserved1[72]; + ULONG SessionId; + BYTE Reserved2[4]; + FILETIME ConnectTime; + FILETIME DisconnectTime; + FILETIME LastInputTime; + FILETIME LoginTime; + BYTE Reserved3[1096]; + FILETIME CurrentTime; +} WINSTATION_INFO, *PWINSTATION_INFO; + +/* end wtsapi32.h */ + #include /* undocumented structures */ @@ -126,7 +204,6 @@ typedef struct { } MIB_UDPEXTABLE, *PMIB_UDPEXTABLE; /* end undocumented structures */ - typedef DWORD (CALLBACK *LPGETIPFORWARDTABLE)(PMIB_IPFORWARDTABLE, PULONG, BOOL); typedef DWORD (CALLBACK *LPGETIFTABLE)(PMIB_IFTABLE, PULONG, BOOL); @@ -153,6 +230,24 @@ typedef BOOL (CALLBACK *LPENUMMODULES)(HANDLE, HMODULE*, typedef DWORD (CALLBACK *LPGETMODULENAME)(HANDLE, HMODULE, LPTSTR, DWORD); +typedef BOOLEAN (CALLBACK *LPSTATIONQUERYINFO)(HANDLE, + ULONG, + WINSTATION_INFO_CLASS, + PVOID, ULONG, PULONG); + +typedef BOOL (CALLBACK *LPWTSENUMERATESESSIONS)(HANDLE, + DWORD, + DWORD, + PWTS_SESSION_INFO *, + DWORD *); + +typedef void (CALLBACK *LPWTSFREEMEMORY)(PVOID); + +typedef BOOL (CALLBACK *LPWTSQUERYSESSION)(HANDLE, + DWORD, + WTS_INFO_CLASS, + LPSTR *, DWORD *); + /* no longer in the standard header files */ typedef struct { LARGE_INTEGER IdleTime; @@ -187,6 +282,8 @@ struct sigar_t { HINSTANCE ip_handle; HINSTANCE nt_handle; HINSTANCE ps_handle; + HINSTANCE wts_handle; + HINSTANCE sta_handle; LPGETIFTABLE get_if_table; LPGETIPFORWARDTABLE get_ipforward_table; LPGETTCPTABLE get_tcp_table; @@ -199,6 +296,10 @@ struct sigar_t { LPENUMMODULES enum_modules; LPGETMODULENAME get_module_name; sigar_win32_pinfo_t pinfo; + LPSTATIONQUERYINFO query_station; + LPWTSENUMERATESESSIONS wts_enum_sessions; + LPWTSFREEMEMORY wts_free; + LPWTSQUERYSESSION wts_query_session; WORD ws_version; int ws_error; LPBYTE peb; //scratch pad for getting peb info diff --git a/src/os/win32/win32_sigar.c b/src/os/win32/win32_sigar.c index bfefe9d0..eb4f78a6 100644 --- a/src/os/win32/win32_sigar.c +++ b/src/os/win32/win32_sigar.c @@ -258,6 +258,20 @@ int sigar_os_open(sigar_t **sigar) (*sigar)->ps_handle = NULL; } + if ((h = LoadLibrary("wtsapi32.dll"))) { + (*sigar)->wts_handle = h; + } + else { + (*sigar)->wts_handle = NULL; + } + + if ((h = LoadLibrary("winsta.dll"))) { + (*sigar)->sta_handle = h; + } + else { + (*sigar)->sta_handle = NULL; + } + (*sigar)->pinfo.pid = -1; (*sigar)->ws_version = 0; (*sigar)->ncpu = 0; @@ -288,6 +302,14 @@ int sigar_os_close(sigar_t *sigar) FreeLibrary(sigar->ps_handle); } + if (sigar->wts_handle) { + FreeLibrary(sigar->wts_handle); + } + + if (sigar->sta_handle) { + FreeLibrary(sigar->sta_handle); + } + if (sigar->ws_version != 0) { WSACleanup(); } @@ -2061,6 +2083,8 @@ int sigar_who_list_get_win32(sigar_t *sigar, sigar_who_registry(sigar, wholist); + sigar_who_wts(sigar, wholist); + return SIGAR_OK; } @@ -2235,3 +2259,123 @@ static int sigar_who_registry(sigar_t *sigar, return SIGAR_OK; } + +static int sigar_who_wts(sigar_t *sigar, + sigar_who_list_t *wholist) +{ + DWORD count, i; + WTS_SESSION_INFO *sessions = NULL; + + if (!sigar->wts_enum_sessions && sigar->wts_handle) { + sigar->wts_enum_sessions = + (LPWTSENUMERATESESSIONS)GetProcAddress(sigar->wts_handle, + "WTSEnumerateSessionsA"); + sigar->wts_free = + (LPWTSFREEMEMORY)GetProcAddress(sigar->wts_handle, + "WTSFreeMemory"); + sigar->wts_query_session = + (LPWTSQUERYSESSION)GetProcAddress(sigar->wts_handle, + "WTSQuerySessionInformationA"); + sigar->query_station = + (LPSTATIONQUERYINFO)GetProcAddress(sigar->sta_handle, + "WinStationQueryInformationW"); + } + if (!sigar->wts_enum_sessions) { + return ENOENT; + } + + if (!sigar->wts_enum_sessions(0, 0, 1, &sessions, &count)) { + return GetLastError(); + } + + for (i=0; iwts_query_session(0, + sessionId, + WTSClientProtocolType, + &buffer, + &bytes)) + { + DWORD type = *buffer; + sigar->wts_free(buffer); + + if (type == WTS_PROTOCOL_TYPE_CONSOLE) { + continue; + } + } + + SIGAR_WHO_LIST_GROW(wholist); + who = &wholist->data[wholist->number++]; + + SIGAR_SSTRCPY(who->device, sessions[i].pWinStationName); + + buffer = NULL; + bytes = 0; + if (sigar->wts_query_session(0, + sessionId, + WTSClientAddress, + &buffer, + &bytes)) + { + PWTS_CLIENT_ADDRESS client = + (PWTS_CLIENT_ADDRESS)buffer; + + sprintf(who->host, "%u.%u.%u.%u", + client->Address[2], + client->Address[3], + client->Address[4], + client->Address[5]); + + sigar->wts_free(buffer); + } + else { + SIGAR_SSTRCPY(who->host, "unknown"); + } + + buffer = NULL; + bytes = 0; + if (sigar->wts_query_session(0, + sessionId, + WTSUserName, + &buffer, + &bytes)) + { + SIGAR_SSTRCPY(who->user, buffer); + sigar->wts_free(buffer); + } + else { + SIGAR_SSTRCPY(who->user, "unknown"); + } + + buffer = NULL; + bytes = 0; + if (sigar->query_station(0, + sessionId, + WinStationInformation, + &station_info, + sizeof(station_info), + &bytes)) + { + who->time = + FileTimeToTime(&station_info.ConnectTime) / 1000000; + } + else { + who->time = 0; + } + } + + sigar->wts_free(sessions); + + return SIGAR_OK; +}