WTSGetActiveConsoleSessionId returns a system session

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 starts, you first need to impersonate a registered user (active user) in order to load some paths and settings that are saved in the data folder of user applications. The code I use works fine every time a new user logs into Windows, unless the service received the impersonation incorrectly and impersonated a system session instead of actie. As I said, this happened only once, but I can’t say why.

Here's how I check which session is active and how the impersonation is performed:

first, when the service detects a login event, it requests an active session identifier, 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 identifier returned by WTSGetActiveConsoleSessionId ().

Then I request the user token using WTSQueryUserToken

Then, if successful, 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 obtained from GetTokenInformation

And if all of the above succeeds, it calls

 DuplicateTokenEx( hImpersonationToken, 0, NULL, SecurityImpersonation, TokenPrimary, phUserToken ); CloseHandle( hImpersonationToken ); 

and if he succeeds, then he personifies the extracted token

 ImpersonateLoggedOnUser(phUserToken); 

My service writes to the log file and, according to the log, all previous calls that were successful, even after the impersonation, the service loaded the system profile, not the user.

Now this problem happened once when I restarted my machine, but I did not even play it again, and I tried for several weeks.

I'm not sure how possible it is for a system profile session to be an active session. I just want to know that I am doing something wrong, not sure if I am using the wrong information class when I request session information or something like that.

Also want to know if it can determine if the requested session is really a system session before impersonating the returned token in order to repeat the issuance again?

As I said, all the calls mentioned check their objects and return codes before proceeding to the next step, so there were no errors in the calls, since it should not continue with impersonation, but it happened: (

Would thank any help possible ... thanks.

+4
source share
1 answer

WTSGetActiveConsoleSessionId () can actually return session 0 when it starts from the service and depending on the version of Windows it is running on.

The way to do what you want is to list all the sessions whose location is connected (session 0 is disconnected) and then impersonate the user of that session. The code below works well on my box.

 //Function to run a process as active user from windows service void ImpersonateActiveUserAndRun(WCHAR* path, WCHAR* args) { DWORD session_id = -1; DWORD session_count = 0; WTS_SESSION_INFOA *pSession = NULL; if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSession, &session_count)) { //log success } else { //log error return; } for (int i = 0; i < session_count; i++) { session_id = pSession[i].SessionId; 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)) { wts_connect_state = *ptr_wts_connect_state; ::WTSFreeMemory(ptr_wts_connect_state); if (wts_connect_state != WTSActive) continue; } else { //log error continue; } HANDLE hImpersonationToken; if (!WTSQueryUserToken(session_id, &hImpersonationToken)) { //log error continue; } //Get real token from impersonation token DWORD neededSize1 = 0; HANDLE *realToken = new HANDLE; if (GetTokenInformation(hImpersonationToken, (::TOKEN_INFORMATION_CLASS) TokenLinkedToken, realToken, sizeof(HANDLE), &neededSize1)) { CloseHandle(hImpersonationToken); hImpersonationToken = *realToken; } else { //log error continue; } HANDLE hUserToken; if (!DuplicateTokenEx(hImpersonationToken, //0, //MAXIMUM_ALLOWED, TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS | MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hUserToken)) { //log error continue; } // Get user name of this process //LPTSTR pUserName = NULL; WCHAR* pUserName; DWORD user_name_len = 0; if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_id, WTSUserName, &pUserName, &user_name_len)) { //log username contained in pUserName WCHAR string } //Free memory if (pUserName) WTSFreeMemory(pUserName); ImpersonateLoggedOnUser(hUserToken); STARTUPINFOW StartupInfo; GetStartupInfoW(&StartupInfo); StartupInfo.cb = sizeof(STARTUPINFOW); //StartupInfo.lpDesktop = "winsta0\\default"; PROCESS_INFORMATION processInfo; SECURITY_ATTRIBUTES Security1; Security1.nLength = sizeof SECURITY_ATTRIBUTES; SECURITY_ATTRIBUTES Security2; Security2.nLength = sizeof SECURITY_ATTRIBUTES; void* lpEnvironment = NULL; // Get all necessary environment variables of logged in user // to pass them to the new process BOOL resultEnv = CreateEnvironmentBlock(&lpEnvironment, hUserToken, FALSE); if (!resultEnv) { //log error continue; } WCHAR PP[1024]; //path and parameters ZeroMemory(PP, 1024 * sizeof WCHAR); wcscpy(PP, path); wcscat(PP, L" "); wcscat(PP, args); // Start the process on behalf of the current user BOOL result = CreateProcessAsUserW(hUserToken, NULL, PP, //&Security1, //&Security2, NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, //lpEnvironment, NULL, //"C:\\ProgramData\\some_dir", NULL, &StartupInfo, &processInfo); if (!result) { //log error } else { //log success } DestroyEnvironmentBlock(lpEnvironment); CloseHandle(hImpersonationToken); CloseHandle(hUserToken); CloseHandle(realToken); RevertToSelf(); } WTSFreeMemory(pSession); } 
+4
source

Source: https://habr.com/ru/post/1383603/


All Articles