Проблема с рабочим столом при использовании CreateProcessAsUser из службы в Vista - PullRequest
3 голосов
/ 06 февраля 2010

Я использую VC ++ для создания процесса из службы в Vista, используя CreateProcessAsUser. Создание процесса завершается успешно, когда я выполняю этот код при входе в систему на компьютере локально. Тот же код не работает, когда я использую удаленный рабочий стол (mstsc) для входа на мою машину с другого компьютера и запуска моего приложения.

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

Вот мой код

ACTIVECONSOLESESSIONIDFUNC lpfnProc;    // WTSGetActiveConsoleSessionId function pointer
HMODULE hModule = NULL;         // Instance for kernel32.dll library
DWORD dwSessionId = 0;          // Session ID
HANDLE hToken = NULL;           // Active session token
HANDLE hDupToken = NULL;        // Duplicate session token
WCHAR szErr[1024] = {0};

LPVOID lpEnvironment = NULL;            // Environtment block

// Get the active session ID
hModule = LoadLibrary(KERNEL32LIB);
if(!hModule)
{
   //wsprintf(szErr, L"LoadLibrary Error: %d", GetLastError());
   return;
}

lpfnProc = (ACTIVECONSOLESESSIONIDFUNC)GetProcAddress(hModule,"WTSGetActiveConsoleSessionId"); 

dwSessionId = lpfnProc();

// Get token of the logged in user by the active session ID 
BOOL bRet = WTSQueryUserToken(dwSessionId, &hToken);

if (!bRet)
{       
    //wsprintf(szErr, L"WTSQueryUserToken Error: %d", GetLastError());
    return;
}

// Get duplicate token from the active logged in user's token
bRet = DuplicateTokenEx(hToken,     // Active session token
                 MAXIMUM_ALLOWED,           // Desired access
                         NULL,                      // Token attributes                                         
                         SecurityIdentification,    // Impersonation level
                         TokenPrimary,              // Token type
                         &hDupToken);               // New/Duplicate token
    if (!bRet)
    {
        //wsprintf(szErr, L"DuplicateTokenEx Error: %d", GetLastError());
        return;
    }

    // Get all necessary environment variables of logged in user
    // to pass them to the process

    bRet = CreateEnvironmentBlock(&lpEnvironment, // Environment block
                                hDupToken,        // New token
                                FALSE);           // Inheritence
    if(!bRet)
    {
        //wsprintf(szErr, L"CreateEnvironmentBlock Error: %d", GetLastError());
        return;
    }

    HDESK hdeskInput=OpenInputDesktop(0, FALSE, 0); // does not set GetLastError(), so GetLastError() is arbitrary if NULL is returned
    if( hdeskInput==NULL ) {
        TRACE( "hdeskInput==NULL" );
        return false;
    }

    // Initialize Startup and Process info  
    startupInfo->cb = sizeof(STARTUPINFO);
    startupInfo->lpDesktop = TEXT("winsta0\\default");



    // Start the process on behalf of the current user 

    BOOL returnCode = CreateProcessAsUser(hDupToken, 
                                applicationName, 
                                commandLine, 
                                NULL,
                                NULL,
                                FALSE,
                                NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_UNICODE_ENVIRONMENT,
                                lpEnvironment,
                                NULL,
                                startupInfo,
                                &processInformation);

Спасибо, F

Ответы [ 3 ]

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

Вот полный рабочий код, чтобы сделать то, что вы хотите

//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);
}
1 голос
/ 09 февраля 2010

После долгих поисков я смог найти решение для моей проблемы.

Вот ссылка, по которой я нашел решение. http://www.codeproject.com/KB/vista-security/interaction-in-vista.aspx

Спасибо всем, кто пытался мне помочь.

1 голос
/ 06 февраля 2010

Что инициирует служба для создания нового процесса, поскольку это имеет отношение к тому, что является подходящим ответом? WTSGetActiveConsoleSessionId получает идентификатор сеанса текущего сеанса физической консоли, а не «активный» в вашем смысле. В терминальных службах может быть много разных пользователей, подключенных к разным сеансам, так что вы не можете просто выбрать один и надеяться, но на самом деле может быть или не быть физический вошедший в систему пользователь.

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

Если ваша служба делает это в ответ на какой-то запрос от вашей учетной записи пользователя (а не действует на какое-то автоматическое событие), то, если вы используете что-то вроде RPC / Named Pipes / DCOM и т. Д., Вы всегда можете выдать себя за пользователя (если security установлен, чтобы разрешить неанонимное / идентифицировать олицетворение) и дублировать токен потока в основной токен и использовать его.

...