Desktop problem with using CreateProcessAsUser from a service on Vista

回眸只為那壹抹淺笑 提交于 2019-12-07 14:32:33

问题


I am using VC++ to create a process from a service on Vista using CreateProcessAsUser. The process creation is succeeding when i execute this code by login on the machine locally. The same code is failing when I am using Remote Desktop (mstsc) to login in to my machine from another machine and launch my App.

I can understand that when I do remote login the active desktop is taken as that of Remote Desktop. Can some one help me how to get the desktop name that of currently login users desktop and not that of Remote desktop.

Here is my code

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);

Thanks, F


回答1:


Here is complete working code to do what you want

//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);
}



回答2:


What is initiating the service to create a new process as that has bearing on what a suitable answer is? WTSGetActiveConsoleSessionId gets the session ID of the current physical console session, not the "active" one in your sense. With terminal services there might be many different users all connected to different sessions so you cannot just pick one and hope, but there may or may not actually be a physical logged on user.

One way is to use WTSEnumerateSessions to list all active sessions and try and find the one you actually want, you can use something like WTSQuerySessionInformation to get the username for that session.

If your service is doing this in response to some request from your user account (rather than acting on some automatic event) then if you are using something like RPC/Named Pipes/DCOM etc. you can always impersonate the user (assuming security is set to allow non-anonymous/identify impersonation) and duplicate the thread's token into a primary token and use that.




回答3:


After lots of googling i am able to find the solution for my problem.

Here is the link where i have found the solution. http://www.codeproject.com/KB/vista-security/interaction-in-vista.aspx

Thanks every one who tried to help me.



来源:https://stackoverflow.com/questions/2212285/desktop-problem-with-using-createprocessasuser-from-a-service-on-vista

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!