我们新建了一个网络映射,现在需要在我们的服务进程中访问这个远程磁盘,结果发现QueryDosDevice、NetUseEnum、GetLogicalDriveStrings均不可用。怎么办?
因为磁盘映射是和当前账户关联的,当账户登录之后才会存在这个盘符。(可以试试在同一个系统上建立两个账户,它们可以将不同的网络位置映射成同一个盘符。当然盘符只是一个逻辑符号,系统正真的符号是\Device\Mup和\Device\LanmanRedirector 的UNC形式标识,这样系统内部是不会重复的)。
我们的磁盘映射是Administrator账户创建的,而服务进程是SYSTEM账户。试了好多种方法都没有解决如何高效的在SYSTEM账户下的访问远程磁盘。
于是想能不能在SYSTEM账户下模拟Administrator的账户访问呢,问了公司的大神后觉得可行。就上网查找相关的资料。顺便这里记录一下以备以后查看。
方法如下:
-
1.得到当前登录用户的Token。
WTSGetActiveConsoleSessionId()
WTSQueryUserToken()
-
2.模拟当前登录用户
ImpersonateLoggedOnUser()
-
3.接下来可以使用本地磁盘的函数进行操作了
。。。。。。。。。
-
4.操作完成之后别忘了RevertToSelf。再换回SYSTEM。
程序中的代码:
头文件
1
2
|
#include <Wtsapi32.h>
#pragma comment(lib, "Wtsapi32.lib")
|
1.如果当前账户是SYSTEM,需要切换到当前激活账户的环境来执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
HANDLE
hTokenUser = NULL;
DWORD
ConsoleSessionId = 0;
BOOL
bImpersonateLoggedOnUser = FALSE;
char
userName[256] = {0};
DWORD
userNameLen =
sizeof
(userName);
GetUserName(userName, &userNameLen);
if
(0 == stricmp(
"SYSTEM"
, userName))
{
// 得到当前激活用户的会话ID
ConsoleSessionId = WTSGetActiveConsoleSessionId();
// 得到当前登录用户的令牌
if
(WTSQueryUserToken(ConsoleSessionId, &hTokenUser))
{
// 模仿成当前登录用户
bImpersonateLoggedOnUser = ImpersonateLoggedOnUser(hTokenUser);
}
}
|
2.用完后
1
2
3
4
5
|
// 终止模拟,返回
if
(bImpersonateLoggedOnUser)
{
RevertToSelf();
}
|
注意事项:
1.该功能可能不支持Win2003以下版本的系统,我还没测试。
2.这里说的当前登录用户指的是哪个用户?看MSDN上的这一段话:
The session identifier of the session that is attached to the physical console. If there is no session attached to the physical console, (for example, if the physical console session is in the process of being attached or detached), this function returns 0xFFFFFFFF.
参考资料:
http://www.programlife.net/impersonateloggedonuser.html
http://hi.baidu.com/robinwjbgui/blog/item/7ab0a213b2b2bf866438db10.html
http://msdn.microsoft.com/en-us/library/windows/desktop/aa378612(v=vs.85).aspx
http://msdn.microsoft.com/en-us/library/aa383835(v=vs.85).aspx
===============================
2014-11-26更新:
接受老大的建议:上述代码中有一处不严谨。判断是否有SYSTEM权限比判用户名更好。
判断代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
BOOL
CurrentUserIsLocalSystem()
{
BOOL
bIsLocalSystem = FALSE;
PSID psidLocalSystem;
SID_IDENTIFIER_AUTHORITY ntAuthority = SECURITY_NT_AUTHORITY;
BOOL
fSuccess = ::AllocateAndInitializeSid(&ntAuthority, 1, SECURITY_LOCAL_SYSTEM_RID,
0, 0, 0, 0, 0, 0, 0, &psidLocalSystem);
if
(fSuccess)
{
fSuccess = ::CheckTokenMembership(0, psidLocalSystem, &bIsLocalSystem);
::FreeSid(psidLocalSystem);
}
return
bIsLocalSystem;
}
|
参考资料: