C++ WTSGetActiveConsoleSessionId返回系统会话
我有一个曾经发生过的问题,我仍然不知道如何解决它。我有一个windows服务,当该服务运行时,它首先需要模拟登录用户(活动用户),以加载保存在用户的应用程序数据文件夹中的一些路径和设置。每次新用户登录到windows时,我使用的代码都能正常工作,但有一次服务错误地模拟了系统会话,而不是actie会话。正如我所说,这只发生过一次,但我真的不知道为什么 这是我检查活动会话的方式,以及模拟是如何完成的: 首先,当服务检测到登录事件时,它通过调用C++ WTSGetActiveConsoleSessionId返回系统会话,c++,windows,windows-7,windows-services,impersonation,C++,Windows,Windows 7,Windows Services,Impersonation,我有一个曾经发生过的问题,我仍然不知道如何解决它。我有一个windows服务,当该服务运行时,它首先需要模拟登录用户(活动用户),以加载保存在用户的应用程序数据文件夹中的一些路径和设置。每次新用户登录到windows时,我使用的代码都能正常工作,但有一次服务错误地模拟了系统会话,而不是actie会话。正如我所说,这只发生过一次,但我真的不知道为什么 这是我检查活动会话的方式,以及模拟是如何完成的: 首先,当服务检测到登录事件时,它通过调用 WTSGetActiveConsoleSessionId
WTSGetActiveConsoleSessionId();
然后,它通过调用WTSQuerySessionInformation检查会话是否处于活动状态(已连接),如下所示:
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);
}
DWORD neededSize = 0;
HANDLE *realToken = new HANDLE;
if(GetTokenInformation(hImpersonationToken, (::TOKEN_INFORMATION_CLASS) TokenLinkedToken, realToken, sizeof(HANDLE), &neededSize))
{
CloseHandle(hImpersonationToken);
hImpersonationToken = *realToken;
}
其中hImpersonationToken是从GetTokenInformation
如果以上所有操作都成功,它将调用
DuplicateTokenEx( hImpersonationToken,
0,
NULL,
SecurityImpersonation,
TokenPrimary,
phUserToken );
CloseHandle( hImpersonationToken );
如果成功,则使用检索到的令牌进行模拟
ImpersonateLoggedOnUser(phUserToken);
“我的服务”会写入日志文件,并根据日志记录以前所有成功的调用,但在模拟之后,服务会加载系统配置文件而不是用户
现在这个问题在我重新启动机器时发生过一次,但我甚至没有再复制它,我已经试了好几个星期了
我不确定系统配置文件会话如何成为活动会话。我只是想知道我在那里是否做错了什么,不确定我在查询会话信息或其他信息时是否使用了错误的信息类
还想知道在使用返回的令牌进行模拟之前,是否可以确定查询的会话是否实际上是系统会话,以便再次重试模拟
正如我所说,在进入下一步之前,所有提到的调用都会检查它们的返回对象和代码,这样它们就不会在调用中出现任何错误,因为它不应该继续模拟,但它确实:(
非常感谢您的帮助…谢谢。WTSGetActiveConsoleSessionId()在从服务运行时可能实际返回会话0,具体取决于它运行的Windows版本 执行所需操作的方法是枚举所有会话,找到已连接的会话(会话0已断开连接),然后模拟该会话的用户。下面的代码在我的框中运行良好
//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);
}
//从windows服务以活动用户身份运行进程的函数
void impersonateActivateUserAndRun(WCHAR*path,WCHAR*args)
{
DWORD会话_id=-1;
DWORD会话计数=0;
WTS_SESSION_INFOA*pSession=NULL;
if(WTSEnumerateSessions(WTS_当前_服务器_句柄、0、1、PSSession和会话计数))
{
//日志成功
}
其他的
{
//日志错误
返回;
}
for(int i=0;i