Как правильно олицетворять пользователя из сервиса?

Я работаю в сервисе, который должен выдавать себя за зарегистрированного пользователя.

Мой код до сих пор, с основной обработкой ошибок:

 // 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 stuffif ( !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.

Службы и приложения, которые вызывают LoadUserProfile, должны проверить, есть ли у пользователя профиль в роуминге. Если у пользователя есть перемещаемый профиль, укажите его путь в качестве члена lpProfilePath в PROFILEINFO. Чтобы получить путь к перемещаемому профилю пользователя, вы можете вызвать функцию NetUserGetInfo, указав уровень информации 3 или 4.

После успешного возврата член hProfile в PROFILEINFO является дескриптором ключа реестра, открытым для корня куста пользователя. Он был открыт с полным доступом (KEY_ALL_ACCESS). Если службе, которая олицетворяет пользователя, необходимо выполнить чтение или запись в файл реестра пользователя, используйте этот дескриптор вместо HKEY_CURRENT_USER. Не закрывайте ручку hProfile. Вместо этого передайте его в функцию UnloadUserProfile.

Если я использую свой код, как сейчас, то он работает. Однако это немного странно, потому что сначала я должен выдать себя за вошедшего в систему пользователя, а затем прекратить олицетворение, чтобы загрузить профиль пользователя. Если я не заканчиваю олицетворение, тогда LoadUserProfile завершится с ошибкой 5 (доступ запрещен). И после успешного завершения LoadUserProfile я должен снова выдать себя за пользователя?

Итак, мой вопрос, это должно быть сделано таким образом, или я делаю что-то не так?
Другой вопрос заключается в том, что если LoadUserProfile преуспел, я мог бы использовать hProfile в качестве дескриптора для реестра пользователей, вошедших в систему. Вопрос как? Потому что для использования RegOpenKeyEy и RegSetValueEx мне нужно передать HKEY, а не HANDLE. Так как я могу использовать эту ручку?

Поблагодарить!

4

Решение

Вам не нужно звонить 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 );

Что касается реестра, то hProfile ручка открыта HKEY для пользователя HKEY_CURRENT_USER дерево. Симпи набрать его из HANDLE в HKEY при передаче его в функции реестра API. Он уже открыт, поэтому вам не нужно звонить RegOpenKeyEx() чтобы снова открыть тот же ключ, но вы можете использовать его в качестве корневого ключа при создании / открытии подразделов или чтении / записи значений в корневом ключе.

6

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]