kam*_*mpi 4 c++ windows service impersonation
我正在使用一项服务,该服务应模拟已登录的用户.
我的代码到目前为止,基本的错误处理:
// 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;
}
Run Code Online (Sandbox Code Playgroud)
根据MSDN:
当用户以交互方式登录时,系统会自动加载用户的配置文件.如果服务或应用程序模拟用户,则系统不会加载用户的配置文件.因此,服务或应用程序应使用LoadUserProfile加载用户的配置文件.
调用LoadUserProfile的服务和应用程序应检查用户是否具有漫游配置文件.如果用户具有漫游配置文件,请将其路径指定为PROFILEINFO的lpProfilePath成员.要检索用户的漫游配置文件路径,可以调用NetUserGetInfo函数,指定信息级别3或4.
成功返回后,PROFILEINFO的hProfile成员是一个向用户配置单元的根目录打开的注册表键句柄.它已以完全访问权限(KEY_ALL_ACCESS)打开.如果模拟用户的服务需要读取或写入用户的注册表文件,请使用此句柄而不是HKEY_CURRENT_USER.不要关闭hProfile句柄.而是将其传递给UnloadUserProfile函数.
如果我现在使用我的代码,那么它的工作原理.但是它有点奇怪,因为首先我必须冒充登录用户,然后结束模拟,加载用户配置文件.如果我没有结束模拟,那么LoadUserProfile将失败,错误5(访问被拒绝).在LoadUserProfile成功后,我应该再次冒充用户?
所以我的问题是,这意味着这样做,或者我做错了什么?另一个问题是,如果LoadUserProfile成功,我可以使用hProfile作为登录用户注册表的句柄.问题是怎么样的?因为要使用RegOpenKeyEy和RegSetValueEx,我需要传递HKEY,而不是HANDLE.那么我该如何使用这个Handle?
谢谢!
您不需要调用,ImpersonateLoggedOnUser()因为您将用户的令牌传递给LoadUserProfile().打电话ImpersonateLoggedOnUser(),如果你需要调用的API,不要让你的用户令牌传递给他们而已.
如果您阅读其余LoadUserProfile()文档,它会说:
调用进程必须具有SE_RESTORE_NAME和SE_BACKUP_NAME权限.
通过冒充您尝试加载配置文件的用户,您可能会失去这些权限.所以不要冒充用户.
更新:尝试这样的事情:
// 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 );
Run Code Online (Sandbox Code Playgroud)
至于Registry,hProfile句柄是HKEY为用户的HKEY_CURRENT_USER树打开的.的simpy型铸造它HANDLE来HKEY传递,当它到注册表API函数.它已经打开,因此您无需再次调用RegOpenKeyEx()再打开相同的密钥,但可以在创建/打开子密钥或在根密钥中读取/写入值时将其用作根密钥.
| 归档时间: |
|
| 查看次数: |
9226 次 |
| 最近记录: |