views:

273

answers:

2

I've written a program which should query the Terminal Services API and print out some state information about the sessions running on a terminal services box. I'm using the WTSQuerySessionInformation function to do this and it's returning some data but most of the data seems to be missing... Does anyone know why?

Here's my program:

void WTSGetString( HANDLE serverHandle, DWORD sessionid, WTS_INFO_CLASS command, wchar_t* commandStr) 
{
    DWORD bytesReturned = 0;
    LPTSTR pData = NULL;
    if (WTSQuerySessionInformation(serverHandle, sessionid, command, &pData, &bytesReturned))
    {
        wprintf(L"\tWTSQuerySessionInformationW - session %d - %s returned \"%s\"\n", sessionid, commandStr, pData);    
    }
    else
    {
        wprintf(L"\tWTSQuerySessionInformationW - session %d - %s failed - error=%d - ", sessionid, commandStr, GetLastError());
        printLastError(NULL, GetLastError());
    }
    WTSFreeMemory(pData);
}


void ExtractFromWTS( HANDLE serverHandle, DWORD sessionid ) 
{

    WTSGetString(serverHandle, sessionid, WTSInitialProgram, L"WTSInitialProgram");
    WTSGetString(serverHandle, sessionid, WTSApplicationName, L"WTSApplicationName");
    WTSGetString(serverHandle, sessionid, WTSWorkingDirectory, L"WTSWorkingDirectory");
    WTSGetString(serverHandle, sessionid, WTSOEMId, L"WTSOEMId");
    WTSGetString(serverHandle, sessionid, WTSSessionId, L"WTSSessionId");
    WTSGetString(serverHandle, sessionid, WTSUserName, L"WTSUserName");
    WTSGetString(serverHandle, sessionid, WTSWinStationName, L"WTSWinStationName");
    WTSGetString(serverHandle, sessionid, WTSDomainName, L"WTSDomainName");
    WTSGetString(serverHandle, sessionid, WTSConnectState, L"WTSConnectState");
    WTSGetString(serverHandle, sessionid, WTSClientBuildNumber, L"WTSClientBuildNumber");
    WTSGetString(serverHandle, sessionid, WTSClientName, L"WTSClientName");
    WTSGetString(serverHandle, sessionid, WTSClientDirectory, L"WTSClientDirectory");
    WTSGetString(serverHandle, sessionid, WTSClientProductId, L"WTSClientProductId");
    WTSGetString(serverHandle, sessionid, WTSClientHardwareId, L"WTSClientHardwareId");
    WTSGetString(serverHandle, sessionid, WTSClientAddress, L"WTSClientAddress");
    WTSGetString(serverHandle, sessionid, WTSClientDisplay, L"WTSClientDisplay");
    WTSGetString(serverHandle, sessionid, WTSClientProtocolType, L"WTSClientProtocolType");
}

int _tmain(int argc, _TCHAR* argv[])
{
    PWTS_SESSION_INFOW ppSessionInfo = 0;
    DWORD pCount;
    if(!WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &ppSessionInfo, &pCount))
    {
        printLastError(L"WTSEnumerateSessions", GetLastError());
        return 1;
    }

    wprintf(L"%d WTS sessions found on host\n", pCount);

    for (unsigned int i=0; i<pCount; i++)
    {
        wprintf(L"> session=%d, stationName = %s\n", ppSessionInfo[i].SessionId, ppSessionInfo[i].pWinStationName);
        ExtractFromWTS(WTS_CURRENT_SERVER_HANDLE, ppSessionInfo[i].SessionId);
        LPWSTR sessionstr = new wchar_t[200];
        wsprintf(sessionstr, L"%d", ppSessionInfo[i].SessionId);    
    }

    return 0;
}

And here's the output:

C:\Users\Administrator\Desktop>ObtainWTSStartShell.exe empserver1
4 WTS sessions found on host
> session=0, stationName = Services
        WTSQuerySessionInformationW - session 0 - WTSInitialProgram failed - error=87 - The paramete
r is incorrect.

        WTSQuerySessionInformationW - session 0 - WTSApplicationName failed - error=87 - The paramet
er is incorrect.

        WTSQuerySessionInformationW - session 0 - WTSWorkingDirectory returned ""
        WTSQuerySessionInformationW - session 0 - WTSOEMId returned ""
        WTSQuerySessionInformationW - session 0 - WTSSessionId returned ""
        WTSQuerySessionInformationW - session 0 - WTSUserName returned ""
        WTSQuerySessionInformationW - session 0 - WTSWinStationName returned "Services"
        WTSQuerySessionInformationW - session 0 - WTSDomainName returned ""
        WTSQuerySessionInformationW - session 0 - WTSConnectState returned "♦"
        WTSQuerySessionInformationW - session 0 - WTSClientBuildNumber returned ""
        WTSQuerySessionInformationW - session 0 - WTSClientName returned ""
        WTSQuerySessionInformationW - session 0 - WTSClientDirectory returned ""
        WTSQuerySessionInformationW - session 0 - WTSClientProductId returned ""
        WTSQuerySessionInformationW - session 0 - WTSClientHardwareId returned ""
        WTSQuerySessionInformationW - session 0 - WTSClientAddress returned ""
        WTSQuerySessionInformationW - session 0 - WTSClientDisplay returned ""
        WTSQuerySessionInformationW - session 0 - WTSClientProtocolType returned ""
        GetShellProcessNameFromUserPolicy - Error: Unable to open policy key - returned [2]
        GetShellProcessName succeseded - explorer.exe
> session=1, stationName = Console
        WTSQuerySessionInformationW - session 1 - WTSInitialProgram returned ""
        WTSQuerySessionInformationW - session 1 - WTSApplicationName returned ""
        WTSQuerySessionInformationW - session 1 - WTSWorkingDirectory returned ""
        WTSQuerySessionInformationW - session 1 - WTSOEMId returned ""
        WTSQuerySessionInformationW - session 1 - WTSSessionId returned "☺"
        WTSQuerySessionInformationW - session 1 - WTSUserName returned ""
        WTSQuerySessionInformationW - session 1 - WTSWinStationName returned "Console"
        WTSQuerySessionInformationW - session 1 - WTSDomainName returned ""
        WTSQuerySessionInformationW - session 1 - WTSConnectState returned "☺"
        WTSQuerySessionInformationW - session 1 - WTSClientBuildNumber returned ""
        WTSQuerySessionInformationW - session 1 - WTSClientName returned ""
        WTSQuerySessionInformationW - session 1 - WTSClientDirectory returned ""
        WTSQuerySessionInformationW - session 1 - WTSClientProductId returned ""
        WTSQuerySessionInformationW - session 1 - WTSClientHardwareId returned ""
        WTSQuerySessionInformationW - session 1 - WTSClientAddress returned ""
        WTSQuerySessionInformationW - session 1 - WTSClientDisplay returned "?"
        WTSQuerySessionInformationW - session 1 - WTSClientProtocolType returned ""
        GetShellProcessNameFromUserPolicy - Error: Unable to open policy key - returned [2]
        GetShellProcessName succeseded - explorer.exe
> session=3, stationName = RDP-Tcp#0
        WTSQuerySessionInformationW - session 3 - WTSInitialProgram returned ""
        WTSQuerySessionInformationW - session 3 - WTSApplicationName returned ""
        WTSQuerySessionInformationW - session 3 - WTSWorkingDirectory returned ""
        WTSQuerySessionInformationW - session 3 - WTSOEMId returned ""
        WTSQuerySessionInformationW - session 3 - WTSSessionId returned "♥"
        WTSQuerySessionInformationW - session 3 - WTSUserName returned "Administrator"
        WTSQuerySessionInformationW - session 3 - WTSWinStationName returned "RDP-Tcp#0"
        WTSQuerySessionInformationW - session 3 - WTSDomainName returned "EMPSERVER1"
        WTSQuerySessionInformationW - session 3 - WTSConnectState returned ""
        WTSQuerySessionInformationW - session 3 - WTSClientBuildNumber returned "?"
        WTSQuerySessionInformationW - session 3 - WTSClientName returned "APWADEV03"
        WTSQuerySessionInformationW - session 3 - WTSClientDirectory returned "C:\Windows\System32\m
stscax.dll"
        WTSQuerySessionInformationW - session 3 - WTSClientProductId returned "☺"
        WTSQuerySessionInformationW - session 3 - WTSClientHardwareId returned ""
        WTSQuerySessionInformationW - session 3 - WTSClientAddress returned "☻"
        WTSQuerySessionInformationW - session 3 - WTSClientDisplay returned "?"
        WTSQuerySessionInformationW - session 3 - WTSClientProtocolType returned "☻"
        GetShellProcessNameFromUserPolicy - Error: Unable to open policy key - returned [2]
        GetShellProcessName succeseded - explorer.exe
> session=65536, stationName = RDP-Tcp
        WTSQuerySessionInformationW - session 65536 - WTSInitialProgram returned ""
        WTSQuerySessionInformationW - session 65536 - WTSApplicationName returned ""
        WTSQuerySessionInformationW - session 65536 - WTSWorkingDirectory returned ""
        WTSQuerySessionInformationW - session 65536 - WTSOEMId returned ""
        WTSQuerySessionInformationW - session 65536 - WTSSessionId returned ""
        WTSQuerySessionInformationW - session 65536 - WTSUserName returned ""
        WTSQuerySessionInformationW - session 65536 - WTSWinStationName returned "RDP-Tcp"
        WTSQuerySessionInformationW - session 65536 - WTSDomainName returned ""
        WTSQuerySessionInformationW - session 65536 - WTSConnectState returned "♠"
        WTSQuerySessionInformationW - session 65536 - WTSClientBuildNumber returned ""
        WTSQuerySessionInformationW - session 65536 - WTSClientName returned ""
        WTSQuerySessionInformationW - session 65536 - WTSClientDirectory returned ""
        WTSQuerySessionInformationW - session 65536 - WTSClientProductId returned ""
        WTSQuerySessionInformationW - session 65536 - WTSClientHardwareId returned ""
        WTSQuerySessionInformationW - session 65536 - WTSClientAddress returned ""
        WTSQuerySessionInformationW - session 65536 - WTSClientDisplay returned ""
        WTSQuerySessionInformationW - session 65536 - WTSClientProtocolType returned ""
        GetShellProcessNameFromUserPolicy - Error: Unable to open policy key - returned [2]
        GetShellProcessName succeseded - explorer.exe

As you can see, some of the data looks valid, but not all....

A: 

I think WTSQuerySessionInformation needs you to obtain privileges first to properly return all data?

Computer Guru
I think that might be the case if you're running against a remote server... but I was running this program locally (i.e. within a Terminal Services session and I don't believe any permissions are required.
Benj
Not permissions. I mean the Windows application privileges that you need to explicitly obtain from code. See here: http://msdn.microsoft.com/en-us/library/bb530716(VS.85).aspxIf this is what you are referring to, then I apologize.
Computer Guru
A: 

Hmm, the answer appears to be that it's fairly normal for these fields to be empty on a terminal services/RDP session. This API was originally a Citrix API and there's a WF equivalent to most of these WTS function. You seem to get much more data from my program when running on a Citrix/IDA server which appears to implement this session API much more fully. Having said that, I also saw more of the fields being filled in when using MS Remote App. However, essentially my program was working...

Benj