Reputation: 914
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
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:
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