Kenny83
Kenny83

Reputation: 914

WTSQueryUserToken throws error 1008, even when running under LocalSystem

I have pretty much the same problem as discussed in WTSQueryUserToken always throws "An attempt was made to reference a token that does not exist" on Windows 7 in C#, but unlike the OP of that question, I'm using C++ on Windows 10 and read the docs properly before starting to code my solution. So my service is most-definitely running under the LocalSystem account.

Here's the relevant part of my SvcInit() function:

    HANDLE hToken;

    // Returns 1, just like in the linked question
    DWORD sessionId = WTSGetActiveConsoleSessionId();

    if (!WTSQueryUserToken(sessionId, &hToken)) {
        // LogError() takes the name of an error-causing function and calls
        // GetLastError() and FormatMessage() to get the system-defined error
        // message, then logs all of that to a file
        LogError("WTSQueryUserToken");
        return;
    }

The docs also mention a need for your service process to have the SE_TCB_NAME privilege. The same paragraph that the other question references:

Obtains the primary access token of the logged-on user specified by the session ID. To call this function successfully, the calling application must be running within the context of the LocalSystem account and have the SE_TCB_NAME privilege.

But by reading https://learn.microsoft.com/en-us/windows/win32/services/localsystem-account, it seems to me as though any process running under the LocalSystem account would automatically have this privilege:

The LocalSystem account has the following privileges:

  • SE_ASSIGNPRIMARYTOKEN_NAME (disabled)
  • SE_AUDIT_NAME (enabled)
  • SE_BACKUP_NAME (disabled)
  • ...many others
  • SE_TCB_NAME (enabled)

So do I need to explicitly add this privilege to my process or not? And what else may be the cause of my issue? MTIA! :-)

Upvotes: 1

Views: 5582

Answers (1)

RbMm
RbMm

Reputation: 33716

in current WTSQueryUserToken exist incomplete phrase:

Among other errors, GetLastError can return one of the following errors.

but in old msdn was list or errors which can return api:

enter image description here

so ERROR_NO_TOKEN mean can be returned if

The token query is for a session in which no user is logged-on. This occurs, for example, when the session is in the idle state or SessionId is zero.

if we try get user token at system startup time of course yet no any logged in user. user simply is unknown and as result not exist and user token (say token containing user sid - but user and unknown, sid is unknown, token can not exist at this time). however service if want can start process exactly when some (any)user logon to system. this need do from HandlerEx callback which registered via RegisterServiceCtrlHandlerEx

we need look for SERVICE_CONTROL_SESSIONCHANGE event. simply code for run process in user session can be like this

DWORD WINAPI HandlerEx(
                       DWORD dwControl,
                       DWORD dwEventType,
                       PVOID lpEventData,
                       PVOID lpContext
                       )
{

    switch (dwControl)
    {
    case SERVICE_CONTROL_SESSIONCHANGE:

        if (dwEventType == WTS_SESSION_LOGON)
        {
            HANDLE hToken;
            if (WTSQueryUserToken(reinterpret_cast<PWTSSESSION_NOTIFICATION>(lpEventData)->dwSessionId, &hToken))
            {
                PVOID lpEnvironment;
                if (CreateEnvironmentBlock(&lpEnvironment, hToken, FALSE))
                {
                    STARTUPINFOW si = { sizeof(si) };
                    PROCESS_INFORMATION pi;
                    if (CreateProcessAsUserW(hToken, 
                        L"c:\\windows\\notepad.exe", 0, 0, 0, 0, 
                        CREATE_UNICODE_ENVIRONMENT, lpEnvironment, 0, &si, &pi))
                    {
                        CloseHandle(pi.hThread);
                        CloseHandle(pi.hProcess);
                    }
                    DestroyEnvironmentBlock(lpEnvironment);
                }
                CloseHandle(hToken);
            }
        }
        break;
    }

    // ...
}

Upvotes: 2

Related Questions