thiroc
thiroc

Reputation: 101

CreateProcessAsUser generating error 5

I've tried mixing the code here and here to run an GUI exe from a service that was initialized through QtService, but whenever I run the code bellow I get an error 5 from the CreateProcessAsUser.

Also, I saw the answer to a similar question here on StackOverflow but couldn't figure out how the DACL is related with the problem, and can't use the answer by Harry Johnson because I wouldn't have the logon info from the users.

So, can someone help me understand why am I receiving the error 5 (Acess Denied) from the code below?

if(initUiWin())
    log->write("InitUiWin executed.");
else {
    QString errorNumber = QString::number(GetLastError());
    log->write("InitUiWin error: " + errorNumber);
}

-

bool initUiWin()
{
    // obtain the currently active session id; every logged on
    // User in the system has a unique session id
    uint dwSessionId = WTSGetActiveConsoleSessionId();

    // obtain the process id of the winlogon process that
    // is running within the currently active session
    QString processName("winlogon.exe");
    DWORD winlogonPID = FindProcessId(processName.toStdWString(),dwSessionId);
    if( winlogonPID != 0 ) {
    HANDLE hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, winlogonPID);
    HANDLE hToken;
    OpenProcessToken(hProcess,TOKEN_READ,&hToken);

    // Security attibute structure used in DuplicateTokenEx and CreateProcessAsUser
    SECURITY_ATTRIBUTES sa;
    sa.nLength = static_cast<DWORD>(sizeof(SECURITY_ATTRIBUTES));

    // copy the access token of the winlogon process;
    // the newly created token will be a primary token
    HANDLE hUserTokenDup;
    if (!DuplicateTokenEx(hToken,MAXIMUM_ALLOWED,&sa,
                            SecurityIdentification,TokenPrimary,&hUserTokenDup)) {
        CloseHandle(hProcess);
        CloseHandle(hToken);
        return false;
    }

    // Get Handle to the interactive window station
    HWINSTA hwinsta = NULL;
    hwinsta = OpenWindowStation(
           _T(L"winsta0"),                   // the interactive window station
           FALSE,                       // handle is not inheritable
           READ_CONTROL | WRITE_DAC);   // rights to read/write the DACL
    if(hwinsta == NULL)
        return false;

    // To get the correct default desktop, set the caller's
    // window station to the interactive window station.
    if (!SetProcessWindowStation(hwinsta))
        return false;

    // Get a handle to the interactive desktop.
    HDESK hdesk = NULL;
    hdesk = OpenDesktop(
          _T(L"default"),     // the interactive window station
          0,             // no interaction with other desktop processes
          FALSE,         // handle is not inheritable
          READ_CONTROL | // request the rights to read and write the DACL
          WRITE_DAC |
          DESKTOP_WRITEOBJECTS |
          DESKTOP_READOBJECTS);
    if(hdesk == NULL)
        return false;

    // Get the SID for the client's logon session.
    PSID pSid = NULL;
    if (!GetLogonSID(hUserTokenDup, &pSid))
          return false;

    // Allow logon SID full access to interactive window station.
    if (!AddAceToWindowStation(hwinsta, pSid) )
          return false;

    // Allow logon SID full access to interactive desktop.
    if (!AddAceToDesktop(hdesk, pSid) )
          return false;

    // Impersonate client to ensure access to executable file.
    if (!ImpersonateLoggedOnUser(hUserTokenDup) )
          return false;

    STARTUPINFO si;
    PROCESS_INFORMATION pi;
    ZeroMemory(&si, sizeof(STARTUPINFO));
    si.cb = static_cast<DWORD>(sizeof(STARTUPINFO));

    // interactive window station parameter; basically this indicates
    // that the process created can display a GUI on the desktop
    wchar_t auxBuffer[16] = L"winsta0\\default";
    si.lpDesktop = auxBuffer;

    // flags that specify the priority and creation method of the process
    int dwCreationFlags = NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE | CREATE_BREAKAWAY_FROM_JOB;

    // create a new process in the current User's logon session
    bool result = CreateProcessAsUser(hUserTokenDup,  // client's access token
                                    L"test-ui-systray.exe",             // file to execute
                                    NULL,  // command line
                                    &sa,           // pointer to process SECURITY_ATTRIBUTES
                                    &sa,           // pointer to thread SECURITY_ATTRIBUTES
                                    false,            // handles are not inheritable
                                    dwCreationFlags,  // creation flags
                                    NULL,      // pointer to new environment block
                                    NULL,             // name of current directory
                                    &si,           // pointer to STARTUPINFO structure
                                    &pi      // receives information about new process
                                    );

    if (pSid)
          FreeLogonSID(&pSid);
    if (hdesk)
          CloseDesktop(hdesk);
    if (hwinsta)
          CloseWindowStation(hwinsta);
    CloseHandle(pi.hThread);
    CloseHandle(pi.hProcess);
    return result;
}

return false;

}

Upvotes: 2

Views: 3348

Answers (1)

thiroc
thiroc

Reputation: 101

Putting it here for visibility. HarryJohnston answered in the comments. The problem was the flags in the OpenProcessToken, I just changed

OpenProcessToken(hProcess,TOKEN_READ,&hToken)

to

OpenProcessToken(hProcess,TOKEN_READ|TOKEN_QUERY|TOKEN_DUPLICATE|TOKEN_ASSIGN_PRIMARY,&hToken)

Upvotes: 2

Related Questions