【发布时间】:2012-01-08 16:35:27
【问题描述】:
我曾经遇到过这个问题,但我仍然不知道如何解决它。我有一个windows服务,当服务运行时,它首先需要模拟登录用户(活动用户)来加载一些保存在用户应用程序数据文件夹中的路径和设置。每次新用户登录到 Windows 时,我使用的代码都能完美运行,除非服务模拟错误并模拟系统会话而不是活动会话。正如我所说,这种情况只发生过一次,但我真的不知道为什么。
这是检查活动会话的方式以及模拟是如何完成的:
首先,当服务检测到登录事件时,它会通过调用查询活动会话 ID
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);
}
其中 session_id 是 WTSGetActiveConsoleSessionId() 返回的会话 ID。
然后我使用WTSQueryUserToken查询用户令牌
如果成功,服务调用GetTokenInformation如下:
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);
我的服务写入一个日志文件,并根据日志所有先前的调用成功但在模拟之后服务加载系统配置文件而不是用户。
现在这个问题在我重新启动机器时发生过一次,但我什至没有再次重现它,我已经尝试了几个星期。
我不确定系统配置文件会话如何成为活动会话。我只是想知道我在那里做错了什么,不确定我在查询会话信息时是否使用了错误的信息类。
还想知道是否有可能在使用返回的令牌进行模拟之前确定查询的会话是否实际上是系统会话,以便可以再次重试模拟?
正如我所说,所有提到的调用都在进入下一步之前检查了它们的返回对象和代码,因此它们不是来自调用的任何错误,因为它不应该继续进行模拟,但确实如此:(
希望能提供任何帮助...谢谢。
【问题讨论】:
标签: c++ windows windows-7 windows-services impersonation