I have this problem that happened once and I still don't know how to fix it. I have a windows service, when the service runs, it first need to impersonate the logged in user (active user) to load some paths and settings that are saved in the user's application data folder. The code that I'm using works perfectly every time a new user logs on to windows except once where the service got the impersonation wrong and impersonated the system session instead of the actie one. As I said this only happened once, but I can't really tell why.
This is how am checking whats the active session and how the impersonation is done:
first when the service detects a logon event it query's the active session ID by calling
WTSGetActiveConsoleSessionId();
then It checks if the session is active(connected) by calling WTSQuerySessionInformation as follows:
WTS_CONNECTSTATE_CLASS wts_connect_state = WTSDisconnected;
WTS_CONNECTSTATE_CLASS* ptr_wts_connect_state = NULL;
DWORD bytes_returned = 0;
if (::WTSQuerySessionInformation(
WTS_CURRENT_SERVER_HANDLE,
session_id,
WTSConnectState,
reinterpret_cast<LPTSTR*>(&ptr_wts_connect_state),
&bytes_returned))
{
ASSERT(bytes_returned == sizeof(*ptr_wts_connect_state));
wts_connect_state = *ptr_wts_connect_state;
::WTSFreeMemory(ptr_wts_connect_state);
return (WTSActive == wts_connect_state);
}
where session_id is the session ID returned by WTSGetActiveConsoleSessionId().
Then I query for the user token using WTSQueryUserToken
Then if that succeeds the service calls GetTokenInformation
as follows:
DWORD neededSize = 0;
HANDLE *realToken = new HANDLE;
if(GetTokenInformation(hImpersonationToken, (::TOKEN_INFORMATION_CLASS) TokenLinkedToken, realToken, sizeof(HANDLE), &neededSize))
{
CloseHandle(hImpersonationToken);
hImpersonationToken = *realToken;
}
where hImpersonationToken is the token retrieved from GetTokenInformation
And if all the above succeeds it then calls
DuplicateTokenEx( hImpersonationToken,
0,
NULL,
SecurityImpersonation,
TokenPrimary,
phUserToken );
CloseHandle( hImpersonationToken );
and if it succeeds then it impersonates with the retrieved token
ImpersonateLoggedOnUser(phUserToken);
My service writes to a log file and according to the log all the previous calls where successful yet after the impersonation the service loaded the system profile instead of the user.
Now this issue happened once when I restarted my machine, yet I wasn't even reproduce it again and I've been trying for weeks.
I'm not sure how its possible for the system profile session to be an active session. I just want to know if I'm doing something wrong there, not sure if I'm using the wrong info class when I'm querying the session info or something.
Also want to know if its possible to determine if the queried session is actually the system session before impersonating with the returned token just so one can retry the impersonation again?
As I said, all mentioned calls have their return objects and codes checked before moving to the next step so their weren't any errors from the calls as it shouldn't continue with the impersonation, yet it did :(
Would appreciate any help possible... thanks.