Getting session info from Terminal Services

So I wanted to retrieve the remote endpoint address for the current Remote Desktop session. Should be easy, right? After all, there's the documented wtsapi32.dll API for retrieving session information, which one would expect to provide this information. Right? No, it doesn't.

What you can retrieve, using the WTSClientAddress request, is the client address, i.e. the local LAN address of the client, which must be self-reported by the client to the server. If the client is behind a NAT:ing firewall, this information is useless.

Oh, and note that the WTS_CLIENT_ADDRESS struct seems to be incorrectly declared in the documentation and in the header file. When I used the wtsapi32 methods to retrieve the client address, I was struck by the strange fact that I had to retrieve the IPv4 address components from the Address member at an offset of two bytes. In retrospect, and looking at the correctly defined WINSTATIONREMOTEADDRESS (see below), I now understand why this happened. And on the subject of messed-up documentation, note that the address is stored as a sequence of four bytes, not as a NULL-terminated string like the documentation says.

For an even more hilarious example, look at the documentation for the WTS_SESSION_ADDRESS structure - here the DWORD AddressFamily is described thus: A null-terminated string that contains the address family. Always set this member to "AF_INET". That one got Facebooked fast.

But I digest.

In the end, I took a look at the Cassia library, which was rumored to be able to provide the information I wanted. Turns out they use another DLL, called winsta.dll, which appears to be wrapped - and dumbed down - by the wtsapi32.dll. While winsta.dll appears to be completely undocumented, I found a few bits and pieces of information here and there and managed to patch together something that works.

(If you want to do this with C#/.NET, you're probably better off using the Cassia library instead)

Here's the code:

#include "stdafx.h"
#include "windows.h"
#include "wtsapi32.h"
 
#include <iostream>
using namespace std;
 
typedef struct _WINSTATIONREMOTEADDRESS {
	DWORD AddressFamily;  // AF_INET, AF_INET6, AF_IPX, AF_NETBIOS, AF_UNSPEC
	DWORD Port;
	BYTE  Address[20];    // client network address
	BYTE Reserved[6];
} WINSTATIONREMOTEADDRESS, * PWINSTATIONREMOTEADDRESS;
 
typedef enum _WINSTATIONINFOCLASS
{
	WinStationCreateData,
	WinStationConfiguration,
	WinStationPdParams,
	WinStationWd,
	WinStationPd,
	WinStationPrinter,
	WinStationClient,
	WinStationModules,
	WinStationInformation,
	WinStationTrace,
	WinStationBeep,
	WinStationEncryptionOff,
	WinStationEncryptionPerm,
	WinStationNtSecurity,
	WinStationUserToken,
	WinStationUnused1,
	WinStationVideoData,
	WinStationInitialProgram,
	WinStationCd,
	WinStationSystemTrace,
	WinStationVirtualData,
	WinStationClientData,
	WinStationSecureDesktopEnter,
	WinStationSecureDesktopExit,
	WinStationLoadBalanceSessionTarget,
	WinStationLoadIndicator,
	WinStationShadowInfo,
	WinStationDigProductId,
	WinStationLockedState,
	WinStationRemoteAddress,
	WinStationIdleTime,
	WinStationLastReconnectType,
	WinStationDisallowAutoReconnect,
	WinStationUnused2,
	WinStationUnused3,
	WinStationUnused4,
	WinStationUnused5,
	WinStationReconnectedFromId,
	WinStationEffectsPolicy,
	WinStationType,
	WinStationInformationEx
} WINSTATIONINFOCLASS;
 
 
int _tmain(int argc, _TCHAR* argv[])
{
	typedef BOOLEAN (WINAPI * PWINSTATIONQUERYINFORMATIONW)(HANDLE, ULONG, WINSTATIONINFOCLASS, PVOID, ULONG, PULONG ); 
	HANDLE hServer = NULL; 
	HMODULE hWinSta = NULL; 
	ULONG RetLen; 
	PWINSTATIONQUERYINFORMATIONW WinStationQueryInformationW = NULL; 
	hWinSta = LoadLibrary(L"WINSTA.DLL"); 
	WinStationQueryInformationW = (PWINSTATIONQUERYINFORMATIONW)GetProcAddress(hWinSta,"WinStationQueryInformationW"); 
 
	WINSTATIONREMOTEADDRESS *remoteAddress = new WINSTATIONREMOTEADDRESS();
 
	BOOL result = WinStationQueryInformationW(WTS_CURRENT_SERVER_HANDLE, WTS_CURRENT_SESSION,
		WinStationRemoteAddress,
		(PVOID)remoteAddress,
		sizeof(WINSTATIONREMOTEADDRESS),
		&RetLen);
 
	char rIPAddress[20];
	if (result && remoteAddress != NULL && remoteAddress->AddressFamily == AF_INET) {
		sprintf_s(rIPAddress, sizeof(rIPAddress), "%d.%d.%d.%d", remoteAddress->Address[0], remoteAddress->Address[1], remoteAddress->Address[2], remoteAddress->Address[3]);
		cout << rIPAddress << endl;
	} else {
		cout << "No IPV4 address. Are you running this in a non-RDP session?" << endl;
	}
	return 0;
}

Comments

все о сео тут

hello there and thank you for your info – I've definitely picked up something new from right here.
I did however expertise some technical points using this web site,
since I experienced to reload the site lots of times previous
to I could get it to load properly. I had been wondering if your web host is OK?
Not that I am complaining, but sluggish loading instances times will often affect your placement in google and
could damage your high-quality score if advertising and marketing with Adwords.

Well I'm adding this RSS to my e-mail and can look out for a lot more of your respective
exciting content. Make sure you update this again very soon.

my blog post phen375