WTSGetActiveConsoleSessionId, возвращающий системный сеанс - PullRequest
5 голосов
/ 29 ноября 2011

У меня одна проблема, которая случилась однажды, и я до сих пор не знаю, как ее исправить.У меня есть служба Windows, когда служба запускается, она сначала должна олицетворять вошедшего в систему пользователя (активного пользователя), чтобы загрузить некоторые пути и настройки, которые сохраняются в папке данных приложения пользователя.Код, который я использую, прекрасно работает каждый раз, когда новый пользователь входит в Windows, за исключением одного раза, когда служба неправильно выдавала себя за себя и выдавала себя за системный сеанс вместо actie.Как я уже сказал, это произошло только один раз, но я не могу точно сказать, почему.

Вот как я проверяю, что такое активный сеанс и как выполняется олицетворение:

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

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 - этоИдентификатор сеанса, возвращаемый 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);

Мой сервис записывает в файл журнала и в соответствии с журналом все предыдущие вызовы, где все еще успешно, после олицетворения служба загрузила системупрофиль вместо пользователя.

Теперь эта проблема произошла однажды, когда я перезапустил свой компьютер, но я даже не воспроизводил его снова, и я пытался в течение нескольких недель.

Яне уверен, насколько возможно, чтобы сессия профиля системы была активной сессией.Я просто хочу знать, делаю ли я что-то не так, не уверен, что использую неправильный класс информации, когда запрашиваю информацию о сеансе или что-то в этом роде.

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

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

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

1 Ответ

5 голосов
/ 09 февраля 2016

WTSGetActiveConsoleSessionId () может фактически возвращать сеанс 0 при запуске из службы и в зависимости от версии Windows, в которой он работает.

Способ сделать то, что вы хотите, - перечислить все сеансы, найти тот, который подключен (сеанс 0 отключен), а затем выдать себя за пользователя этого сеанса. Код ниже хорошо работает на моей коробке.

//Function to run a process as active user from windows service
void ImpersonateActiveUserAndRun(WCHAR* path, WCHAR* args)
{
    DWORD session_id = -1;
    DWORD session_count = 0;

    WTS_SESSION_INFOA *pSession = NULL;


    if (WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE, 0, 1, &pSession, &session_count))
    {
        //log success
    }
    else
    {
        //log error
        return;
    }

    for (int i = 0; i < session_count; i++)
    {
        session_id = pSession[i].SessionId;

        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))
        {
            wts_connect_state = *ptr_wts_connect_state;
            ::WTSFreeMemory(ptr_wts_connect_state);
            if (wts_connect_state != WTSActive) continue;
        }
        else
        {
            //log error
            continue;
        }

        HANDLE hImpersonationToken;

        if (!WTSQueryUserToken(session_id, &hImpersonationToken))
        {
            //log error
            continue;
        }


        //Get real token from impersonation token
        DWORD neededSize1 = 0;
        HANDLE *realToken = new HANDLE;
        if (GetTokenInformation(hImpersonationToken, (::TOKEN_INFORMATION_CLASS) TokenLinkedToken, realToken, sizeof(HANDLE), &neededSize1))
        {
            CloseHandle(hImpersonationToken);
            hImpersonationToken = *realToken;
        }
        else
        {
            //log error
            continue;
        }


        HANDLE hUserToken;

        if (!DuplicateTokenEx(hImpersonationToken,
            //0,
            //MAXIMUM_ALLOWED,
            TOKEN_ASSIGN_PRIMARY | TOKEN_ALL_ACCESS | MAXIMUM_ALLOWED,
            NULL,
            SecurityImpersonation,
            TokenPrimary,
            &hUserToken))
        {
            //log error
            continue;
        }

        // Get user name of this process
        //LPTSTR pUserName = NULL;
        WCHAR* pUserName;
        DWORD user_name_len = 0;

        if (WTSQuerySessionInformationW(WTS_CURRENT_SERVER_HANDLE, session_id, WTSUserName, &pUserName, &user_name_len))
        {
            //log username contained in pUserName WCHAR string
        }

        //Free memory                         
        if (pUserName) WTSFreeMemory(pUserName);

        ImpersonateLoggedOnUser(hUserToken);

        STARTUPINFOW StartupInfo;
        GetStartupInfoW(&StartupInfo);
        StartupInfo.cb = sizeof(STARTUPINFOW);
        //StartupInfo.lpDesktop = "winsta0\\default";

        PROCESS_INFORMATION processInfo;

        SECURITY_ATTRIBUTES Security1;
        Security1.nLength = sizeof SECURITY_ATTRIBUTES;

        SECURITY_ATTRIBUTES Security2;
        Security2.nLength = sizeof SECURITY_ATTRIBUTES;

        void* lpEnvironment = NULL;

        // Get all necessary environment variables of logged in user
        // to pass them to the new process
        BOOL resultEnv = CreateEnvironmentBlock(&lpEnvironment, hUserToken, FALSE);
        if (!resultEnv)
        {
            //log error
            continue;
        }

        WCHAR PP[1024]; //path and parameters
        ZeroMemory(PP, 1024 * sizeof WCHAR);
        wcscpy(PP, path);
        wcscat(PP, L" ");
        wcscat(PP, args);

        // Start the process on behalf of the current user 
        BOOL result = CreateProcessAsUserW(hUserToken, 
            NULL,
            PP,
            //&Security1,
            //&Security2,
            NULL,
            NULL,
            FALSE, 
            NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,
            //lpEnvironment,
            NULL,
            //"C:\\ProgramData\\some_dir",
            NULL,
            &StartupInfo,
            &processInfo);

        if (!result)
        {
            //log error
        }
        else
        {
            //log success
        }

        DestroyEnvironmentBlock(lpEnvironment);

        CloseHandle(hImpersonationToken);
        CloseHandle(hUserToken);
        CloseHandle(realToken);

        RevertToSelf();
    }

    WTSFreeMemory(pSession);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...