У меня такая проблема, которая случилась однажды, и я до сих пор не знаю, как ее решить. У меня есть служба 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 - это ID сессии, возвращенный WTSGetActiveConsoleSessionId().
Затем я запрашиваю токен пользователя, используя 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);
Мой сервис пишет в лог файл и согласно логу все предыдущие вызовы были успешными, но после имперсонации сервис загрузил системный профиль вместо пользовательского.
Эта проблема возникла один раз, когда я перезагрузил машину, но я даже не смог воспроизвести ее снова, а я пытался в течение нескольких недель.
Я не уверен, как возможно, чтобы сессия системного профиля была активной сессией. Я просто хочу знать, не делаю ли я что-то не так, не уверен, что использую неправильный класс info при запросе информации о сессии или что-то еще.
Также хотелось бы знать, возможно ли определить, является ли запрашиваемая сессия на самом деле системной сессией, перед тем как имперсонифицироваться с возвращенным токеном, чтобы можно было повторить попытку имперсонизации снова?
Как я уже сказал, все упомянутые вызовы имеют свои возвращаемые объекты и коды, проверенные перед переходом к следующему шагу, так что ошибок от вызовов не было, так как они не должны продолжать имперсонизацию, но они были :(
Буду признателен за любую возможную помощь... спасибо.