VincentHuang
VincentHuang

Reputation: 416

WTSQueryUserToken return 5 (ERROR_ACCESS_DENIED)

I have a program runs as SYSTEM and try to query logon user token by the following code:

WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSessionInfo, &dwCount);
for (i = 0; i < dwCount; i++) {
    WTS_SESSION_INFO si = pSessionInfo[i];
    if (WTSActive == si.State) {
        WTSQueryUserToken(si.SessionId, &hUserToken)
    }
}

The above codes run successfully in Win10. But in Win7 32-bit, WTSQueryUserToken() always return False with error 5 (ERROR_ACCESS_DENIED).

Did I miss any configuration in Win7 environment?

=== Edit ====

My program run as a service which follows the example.

I expect that my program is run as LocalSystem account as the last second argument (NULL) in CreateServer().

Upvotes: 1

Views: 983

Answers (1)

RbMm
RbMm

Reputation: 33716

The previous version of MSDN documentation for WTSQueryUserToken was more complete in terms of possible error values

Error values table

ERROR_ACCESS_DENIED:

The caller does not have the appropriate permissions to call this function. The caller must be running within the context of the LocalSystem account and have the SE_TCB_NAME privilege.

But when the caller does not have SE_TCB_NAME privilege, a different error code is returned:

ERROR_PRIVILEGE_NOT_HELD:

The caller does not have the SE_TCB_NAME privilege.

So ERROR_ACCESS_DENIED is returned when the caller does not run as LocalSystem. Specifically, this means that TokenUser of the caller's token is not S-1-5-18 ( NT AUTHORITY\SYSTEM - WellKnownGroup )

Internally WTSQueryUserToken first checks if SE_TCB_NAME privilege is held and enabled and if it's not it returns ERROR_PRIVILEGE_NOT_HELD.

Otherwise, WinStationQueryInformationW is called with WinStationUserToken. The WINSTATIONUSERTOKEN is returned on success. This is remote call to LSM service, it usually runs in the svchost.exe process with LSM in its command line. A call is handled by lsm.dll, where

RPC_STATUS CALLBACK CPrivateRpc::staticRpcSecurityCallback(void *,int);

is called (this function is inside lsm.dll). Inside it, a function

HRESULT CUtils::IsCallerSystem();

is called. This function checks that TokenUser of the caller's token is S-1-5-18 and if not - CPrivateRpc::staticRpcSecurityCallback drops the call with ERROR_ACCESS_DENIED - and error returned for caller.

So check in which context your code really runs.

Upvotes: 1

Related Questions