Willy K.
Willy K.

Reputation: 432

WTSIsRemoteSession always returns TRUE

I'm currently writing a Windows service, which also does something when a user logs on. There was the idea to do nothing if the logon comes from a remote computer (e.g. Remote desktop), and tried to find a way to dermine this. But following does not work - it always returns true (Windows 10 64 bit V1809) - is there something I doing wrong here?

DWORD SvcHandlerEx(DWORD controlCode, DWORD eventType, ... )
{
    ...

    switch(controlCode)
    {
        case SERVICE_CONTROL_SESSIONCHANGE:
        {
            WTSSESSION_NOTIFICATION *pSessInfo = (WTSSESSION_NOTIFICATION *)pEvtData;
            // invoke SessionChangeHandler(eventId, pSessInfo->dwSessionId)
        }

        ...
    }

    ...
}

...

VOID SessionChangeHandler(DWORD reason, DWORD sessionId)
{
    LPWSTR *pSessionInfo = nullptr;
    DWORD dataLen = 0;
    BOOL isRDP = false;

    if (!WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, 
                                     WTSIsRemoteSession, &pSessionInfo, &dataLen))
    {
        // Do some error handling...
        return;
    }

    if (dataLen)
    {
        if (dataLen)
        {
            isRDP = (bool)pSessionInfo;    // Always 1 (TRUE) !!!
        }

        WTSFreeMemory(pSessionInfo);
    }

    ...

}

Upvotes: 1

Views: 1131

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 596307

Per the documentation for WTSIsRemoteSession:

WTSIsRemoteSession

Determines whether the current session is a remote session.

The WTSQuerySessionInformation function returns a value of TRUE to indicate that the current session is a remote session, and FALSE to indicate that the current session is a local session. This value can only be used for the local machine, so the hServer parameter of the WTSQuerySessionInformation function must contain WTS_CURRENT_SERVER_HANDLE.

Windows Server 2008 and Windows Vista:  This value is not supported.

This implies that the return value of WTSQuerySessionInformation() holds the value you are looking for, and whatever memory the function may allocate, if any, is secondary and should be ignored when querying WTSIsRemoteSession, eg:

VOID SessionChangeHandler(DWORD reason, DWORD sessionId)
{
    LPWSTR *pSessionInfo = nullptr;
    DWORD dataLen = 0;

    bool isRDP = WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSIsRemoteSession, &pSessionInfo, &dataLen);
    if ((!isRDP) && (GetLastError() != 0))
    {
        // Do some error handling...
        return;
    }

    if (pSessionInfo)
        WTSFreeMemory(pSessionInfo);

    // use isRDP as needed...
    ...
}

However, if you find that isRDP is always true in this case, then the documentation is misleading and you should check the contents of the pSessionInfo buffer instead. You are setting your isRDP variable based on whether WTSQuerySessionInformation() allocates any memory at all, you are not looking at what is actually inside the data.

For instance, assuming dataLen is being set to sizeof(BOOL) on output then cast your pSessionInfo pointer to a BOOL* pointer and dereference it, eg:

VOID SessionChangeHandler(DWORD reason, DWORD sessionId)
{
    LPWSTR *pSessionInfo = nullptr;
    DWORD dataLen = 0;

    if (!WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSIsRemoteSession, &pSessionInfo, &dataLen))
    {
        // Do some error handling...
        return;
    }

    bool isRDP = * (BOOL*) pSessionInfo;
    WTSFreeMemory(pSessionInfo);

    // use isRDP as needed...
    ...
}

Alternatively:

VOID SessionChangeHandler(DWORD reason, DWORD sessionId)
{
    BOOL *isRDP = nullptr;
    DWORD dataLen = 0;

    if (!WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSIsRemoteSession, (LPWSTR*)&isRDP, &dataLen))
    {
        // Do some error handling...
        return;
    }

    // use *isRDP as needed...

    WTSFreeMemory(isRDP);
    ...
}

UPDATE:

On the other hand, if dataLen is instead being set to sizeof(UCHAR) on output then cast your pSessionInfo pointer to a UCHAR* pointer and dereference it, eg:

VOID SessionChangeHandler(DWORD reason, DWORD sessionId)
{
    LPWSTR *pSessionInfo = nullptr;
    DWORD dataLen = 0;

    if (!WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSIsRemoteSession, &pSessionInfo, &dataLen))
    {
        // Do some error handling...
        return;
    }

    bool isRDP = * (UCHAR*) pSessionInfo;
    WTSFreeMemory(pSessionInfo);

    // use isRDP as needed...
    ...
}

Alternatively:

VOID SessionChangeHandler(DWORD reason, DWORD sessionId)
{
    UCHAR *isRDP = nullptr;
    DWORD dataLen = 0;

    if (!WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, sessionId, WTSIsRemoteSession, (LPWSTR*)&isRDP, &dataLen))
    {
        // Do some error handling...
        return;
    }

    // use *isRDP as needed...

    WTSFreeMemory(isRDP);
    ...
}

Upvotes: 5

Related Questions