WTSGetActiveConsoleSessionId возвращающий системную сессию

У меня такая проблема, которая случилась однажды, и я до сих пор не знаю, как ее решить. У меня есть служба 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 при запросе информации о сессии или что-то еще.

Также хотелось бы знать, возможно ли определить, является ли запрашиваемая сессия на самом деле системной сессией, перед тем как имперсонифицироваться с возвращенным токеном, чтобы можно было повторить попытку имперсонизации снова?

Как я уже сказал, все упомянутые вызовы имеют свои возвращаемые объекты и коды, проверенные перед переходом к следующему шагу, так что ошибок от вызовов не было, так как они не должны продолжать имперсонизацию, но они были :(

Буду признателен за любую возможную помощь... спасибо.

5
задан Zaid Amir 29 November 2011 в 10:13
поделиться