问题描述
我的代码到目前为止,基本的错误处理:
//获取登录用户的活动控制台会话ID
if(!WTSQueryUserToken(WTSGetActiveConsoleSessionId(),& hToken))
{
ShowErrorText(WTSQueryUserToken failed。,GetLastError(),true);
return;
}
HANDLE hDuplicated;
//复制令牌
if(!DuplicateToken(hToken,SecurityImpersonation,& hDuplicated))
{
ShowErrorText(DuplicateToken failed。,GetLastError ),true);
}
else
{
ShowErrorText(DuplicateToken succeeded。,0,true);
}
//模拟登录的用户
if(!ImpersonateLoggedOnUser(hToken))
{
ShowErrorText(ImpersonateLoggedOnUser failed。,GetLastError (),true);
return;
}
//检索DC名称
if(!GetPrimaryDC(DC))
{
ShowErrorText(GetPrimaryDC failed。 true);
}
PROFILEINFO lpProfileInfo;
ZeroMemory(& lpProfileInfo,sizeof(PROFILEINFO));
lpProfileInfo.dwSize = sizeof(PROFILEINFO);
lpProfileInfo.lpUserName = CurrentUser;
//获取配置文件的类型。漫游,强制或临时
int ret = GetTypeOfProfile();
if(ret == 2)
{
//如果漫游配置文件获取路径
if(!GetRoamingProfilePath(DC,CurrentUser,RoamingProfilePath))
{
ShowErrorText(无法检索漫游配置文件路径。,GetLastError(),true);
}
}
if(RevertToSelf())
{
ShowErrorText(Impersonation successfully successfully。
}
if(!LoadUserProfile(hDuplicated,& lpProfileInfo))
{
ShowErrorText(LoadUserProfile failed。,GetLastError(),true);
}
else
{
ShowErrorText(LoadUserProfile succeeded。,0,true);
}
//做一些东西
if(!UnloadUserProfile(hDuplicated,lpProfileInfo.hProfile))
{
ShowErrorText(UnloadUserProfile failed。,GetLastError(),true);
}
else
{
ShowErrorText(UnloadUserProfile succeeded。,0,true);
}
if(!ImpersonateLoggedOnUser(hToken))
{
ShowErrorText(ImpersonateLoggedOnUser failed。,GetLastError(),true);
return;
}
根据MSDN:
如果我现在使用我的代码,那么它的工作原理。但是它有点奇怪,因为首先我必须模拟登录的用户,然后结束模拟,加载用户配置文件。如果我不结束模拟,然后LoadUserProfile将失败,错误5(访问被拒绝)。在LoadUserProfile成功后,我应该再次模仿用户?
所以我的问题是,这意味着这样做,或者我做错了什么?
另一个问题是,如果LoadUserProfile成功,我可以使用hProfile作为登录用户注册表的句柄。问题是怎么样的?因为要使用RegOpenKeyEy和RegSetValueEx我需要传递一个HKEY,而不是一个HANDLE。
您不需要调用 ImpersonateLoggedOnUser()
,因为您将用户的令牌传递给 LoadUserProfile()
。
<$ p $ $ <$ c $>
p>如果您阅读了 LoadUserProfile()
文档的其余部分,则说明:通过模拟正在尝试为其加载配置文件的用户可能会失去这些特权。
更新:请尝试这样:
//获取登录用户的活动控制台会话ID
DWORD dwSessionID = WTSGetActiveConsoleSessionId();
if(dwSessionID == 0xFFFFFFFF)
{
ShowErrorText(WTSGetActiveConsoleSessionId failed。,GetLastError(),true);
return;
}
if(!WTSQueryUserToken(dwSessionID,& hToken))
{
ShowErrorText(WTSQueryUserToken failed。,GetLastError(),true);
return;
}
//复制令牌
HANDLE hDuplicated = NULL;
if(!DuplicateToken(hToken,SecurityImpersonation,& hDuplicated))
{
ShowErrorText(DuplicateToken failed。,GetLastError(),true);
CloseHandle(hToken);
return;
}
//获取DC名称
if(!GetPrimaryDC(DC))
{
ShowErrorText(GetPrimaryDC failed。 true);
CloseHandle(hDuplicate);
CloseHandle(hToken);
return;
}
PROFILEINFO lpProfileInfo;
ZeroMemory(& lpProfileInfo,sizeof(PROFILEINFO));
lpProfileInfo.dwSize = sizeof(PROFILEINFO);
lpProfileInfo.lpUserName = CurrentUser;
//获取配置文件的类型。漫游,强制或临时
USER_INFO_4 * UserInfo = NULL;
int ret = GetTypeOfProfile();
if(ret == 2)
{
//如果漫游配置文件获取它的路径
if(NetUserGetInfo(DC,CurrentUser,4,(LPBYTE *)& UserInfo)!= NERR_Success)
{
ShowErrorText(NetUserGetInfo failed。,0,true);
CloseHandle(hDuplicated);
CloseHandle(hToken);
return;
}
lpProfileInfo.lpProfilePath = UserInfo-> usri3_profile;
}
if(!LoadUserProfile(hDuplicated,& lpProfileInfo))
{
ShowErrorText(LoadUserProfile failed。,GetLastError(),true);
if(UserInfo)
NetApiBufferFree(UserInfo);
CloseHandle(hDuplicated);
CloseHandle(hToken);
return;
}
if(UserInfo)
NetApiBufferFree(UserInfo);
ShowErrorText(LoadUserProfile succeeded。,0,true);
//做一些东西
if(!UnloadUserProfile(hDuplicated,lpProfileInfo.hProfile))
{
ShowErrorText(UnloadUserProfile failed。 GetLastError(),true);
}
else
{
ShowErrorText(UnloadUserProfile succeeded。,0,true);
}
CloseHandle(hDuplicated);
CloseHandle(hToken);
对于注册表, hProfile
是用户的 HKEY_CURRENT_USER
树中打开的 HKEY
。当将它传递到Registry API函数时,Simpy将其从 HANDLE
类型转换为 HKEY
。它已经打开,因此您不需要调用 RegOpenKeyEx()
再次打开同一个键,但是您可以在创建/打开子键时将其用作根键,或在根键中读取/写入值。
I'm working a service, which should impersonate the logged on user.
My code so far, with basic error handling:
// get the active console session ID of the logged on user
if ( !WTSQueryUserToken( WTSGetActiveConsoleSessionId(), &hToken ) )
{
ShowErrorText( "WTSQueryUserToken failed.", GetLastError( ), true );
return;
}
HANDLE hDuplicated;
// duplicate the token
if ( !DuplicateToken( hToken, SecurityImpersonation, &hDuplicated ) )
{
ShowErrorText( "DuplicateToken failed.", GetLastError( ), true );
}
else
{
ShowErrorText( "DuplicateToken succeeded.", 0, true );
}
// impersonate the logged on user
if ( !ImpersonateLoggedOnUser( hToken ) )
{
ShowErrorText( "ImpersonateLoggedOnUser failed.", GetLastError(), true );
return;
}
// retrieve the DC name
if ( !GetPrimaryDC( DC ) )
{
ShowErrorText( "GetPrimaryDC failed.", 0, true );
}
PROFILEINFO lpProfileInfo;
ZeroMemory( &lpProfileInfo, sizeof( PROFILEINFO ) );
lpProfileInfo.dwSize = sizeof( PROFILEINFO );
lpProfileInfo.lpUserName = CurrentUser;
// get type of profile. roaming, mandatory or temporary
int ret = GetTypeOfProfile();
if ( ret == 2 )
{
// if roaming profile get the path of it
if ( !GetRoamingProfilePath( DC, CurrentUser, RoamingProfilePath ) )
{
ShowErrorText( "Failed to retrieve roaming profile path.", GetLastError(), true );
}
}
if ( RevertToSelf( ) )
{
ShowErrorText( "Impersonation ended successfully.", 0, true );
}
if ( !LoadUserProfile( hDuplicated, &lpProfileInfo ) )
{
ShowErrorText( "LoadUserProfile failed.", GetLastError(), true );
}
else
{
ShowErrorText( "LoadUserProfile succeeded.", 0, true );
}
//do some stuff
if ( !UnloadUserProfile( hDuplicated, lpProfileInfo.hProfile ) )
{
ShowErrorText( "UnloadUserProfile failed.", GetLastError( ), true );
}
else
{
ShowErrorText( "UnloadUserProfile succeeded.", 0, true );
}
if ( !ImpersonateLoggedOnUser( hToken ) )
{
ShowErrorText( "ImpersonateLoggedOnUser failed.", GetLastError( ), true );
return;
}
According to MSDN:
If i use my code as it is now, then it works. However is it a little strange, because first i have to impersonate the logged on user, and then end the impersonation, to Load the users profile. If i don't end the impersonation then LoadUserProfile will fail with error 5 ( Access denied ). And after LoadUserProfile succeeded i should impersonate the user again?
So my question is, this meant to be done this way, or i am doing something wrong?Another question is, that if LoadUserProfile succeeded i could use hProfile as a Handle to the logged on users registry. Question is how? Because to use RegOpenKeyEy and RegSetValueEx i need to pass a HKEY, not a HANDLE. So how can i use this Handle?
Thank!
解决方案 You don't need to call ImpersonateLoggedOnUser()
since you are passing the user's token to LoadUserProfile()
. Call ImpersonateLoggedOnUser()
only if you need to call APIs that do not allow you to pass a user token to them.
If you read the rest of the LoadUserProfile()
documentation, it says:
By impersonating the user you are trying to load a profile for, you are likely losing those privileges. So don't impersonate the user.
Update: Try something like this:
// get the active console session ID of the logged on user
DWORD dwSessionID = WTSGetActiveConsoleSessionId();
if ( dwSessionID == 0xFFFFFFFF )
{
ShowErrorText( "WTSGetActiveConsoleSessionId failed.", GetLastError( ), true );
return;
}
if ( !WTSQueryUserToken( dwSessionID, &hToken ) )
{
ShowErrorText( "WTSQueryUserToken failed.", GetLastError( ), true );
return;
}
// duplicate the token
HANDLE hDuplicated = NULL;
if ( !DuplicateToken( hToken, SecurityImpersonation, &hDuplicated ) )
{
ShowErrorText( "DuplicateToken failed.", GetLastError( ), true );
CloseHandle( hToken );
return;
}
// retrieve the DC name
if ( !GetPrimaryDC( DC ) )
{
ShowErrorText( "GetPrimaryDC failed.", 0, true );
CloseHandle( hDuplicated );
CloseHandle( hToken );
return;
}
PROFILEINFO lpProfileInfo;
ZeroMemory( &lpProfileInfo, sizeof( PROFILEINFO ) );
lpProfileInfo.dwSize = sizeof( PROFILEINFO );
lpProfileInfo.lpUserName = CurrentUser;
// get type of profile. roaming, mandatory or temporary
USER_INFO_4 *UserInfo = NULL;
int ret = GetTypeOfProfile();
if ( ret == 2 )
{
// if roaming profile get the path of it
if ( NetUserGetInfo( DC, CurrentUser, 4, (LPBYTE*)&UserInfo) != NERR_Success )
{
ShowErrorText( "NetUserGetInfo failed.", 0, true );
CloseHandle( hDuplicated );
CloseHandle( hToken );
return;
}
lpProfileInfo.lpProfilePath = UserInfo->usri3_profile;
}
if ( !LoadUserProfile( hDuplicated, &lpProfileInfo ) )
{
ShowErrorText( "LoadUserProfile failed.", GetLastError(), true );
if ( UserInfo )
NetApiBufferFree(UserInfo);
CloseHandle( hDuplicated );
CloseHandle( hToken );
return;
}
if ( UserInfo )
NetApiBufferFree(UserInfo);
ShowErrorText( "LoadUserProfile succeeded.", 0, true );
//do some stuff
if ( !UnloadUserProfile( hDuplicated, lpProfileInfo.hProfile ) )
{
ShowErrorText( "UnloadUserProfile failed.", GetLastError( ), true );
}
else
{
ShowErrorText( "UnloadUserProfile succeeded.", 0, true );
}
CloseHandle( hDuplicated );
CloseHandle( hToken );
As for the Registry, the hProfile
handle is the opened HKEY
for the user's HKEY_CURRENT_USER
tree. Simpy type-cast it from HANDLE
to HKEY
when passing it to Registry API functions. It is already opened, so you do not need to call RegOpenKeyEx()
to open that same key again, but you can use it as the root key when creating/opening subkeys, or reading/writing values in the root key.
这篇关于如何正确地模拟用户从服务?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!