0

I've been banging my head on this for days, and I must have read every page on the Internet even remotely related, but I still can't find an answer. Help!

Here's the scenario: In Windows 7, I have a process running under an admin user account (not a service). It creates a global named mutex, which is later used in a child process running under a regular user account. No matter what I do, or what ACLs I put on the mutex, the child process keeps returning Access Denied when trying to get the handle.

I've distilled my code down into a test app just to experiment with the process and mutex parts, and I found something surprising: if I call OpenMutex from the user app without first creating the mutex, I would expect a Not Found error but I still get Access Denied. However, if I launch the user app from Explorer instead (shift-right-click, Run as different user...), I get the expected behavior. I also noticed that the user app has a plain blocky window border rather than the normal Windows theme when launched from the admin app.

So my guess is that there's something wrong with how I'm launching the user app, but I just can't see what I'm missing.

Here are the relevant parts:

bool CUserTest::LogInUser()
{
    if ((m_hUserToken == NULL) && !LogonUser(TEST_USER_NAME, L".", TEST_USER_PASS, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, &m_hUserToken))
    {
        CloseHandle(m_hUserToken);
        m_hUserToken = NULL;
    }
    return (m_hUserToken != NULL);
}

bool CUserTest::LaunchTestApp()
{
   PROCESS_INFORMATION ProcInfo;
   STARTUPINFO si;
   ZeroMemory(&si, sizeof(STARTUPINFO));
   si.cb = sizeof(si);
   si.lpDesktop = L"winsta0\\default";
   wchar_t wszCmdLine[MAX_PATH + 1] = { 0 };
   wcscpy(wszCmdLine, L"UserTestClient.exe");

   bool bSuccess = false;

   LPVOID pEnv;
   PROFILEINFO sProfileInfo;
   ZeroMemory(&sProfileInfo, sizeof(PROFILEINFO));
   sProfileInfo.dwSize = sizeof(PROFILEINFO);
   sProfileInfo.lpUserName = TEST_USER_NAME;
   if (LoadUserProfile(m_hUserToken, &sProfileInfo))
   {
       if (ImpersonateLoggedOnUser(m_hUserToken))
       {
           if (CreateEnvironmentBlock(&pEnv, m_hUserToken, FALSE))
           {
               bSuccess = CreateProcessAsUser(
                   m_hUserToken,    
                   NULL,
                   wszCmdLine,
                   NULL,            // ProcessAttributes
                   NULL,            // ThreadAttributes
                   FALSE,           // InheritHandles
                   CREATE_UNICODE_ENVIRONMENT,               // CreationFlags
                   pEnv,            // Environment
                   NULL,            // CurrentDirectory
                   &si,
                   &ProcInfo);      // ProcessInformation
               DestroyEnvironmentBlock(pEnv);
           }
           RevertToSelf();
       }
       UnloadUserProfile(m_hUserToken, sProfileInfo.hProfile);
   }

   if (bSuccess)
   {
       CloseHandle(ProcInfo.hThread);
       CloseHandle(ProcInfo.hProcess);
   }

   return bSuccess;
}
Brian
  • 1
  • The problem is unlikely to be related to the way you are creating the process. You need to show the code that opens the mutex. (Do you still get "access denied" rather than "not found" if you reboot the machine first?) – Harry Johnston Dec 09 '15 at 21:34

1 Answers1

0

I never could get the CreateProcessAsUser call to work correctly, but I finally got it working using CreateProcessWithLogonW instead. The trick was to set si.lpDesktop to NULL rather than "winsta0\default", contrary to everything I'd read up to this point.

Brian
  • 1
  • That's ... very odd. A mutex is a kernel object, so the desktop you're running in has no effect. (The Remote Desktop session does, for non-global objects, but that wouldn't produce an Access Denied error.) Perhaps the problem wasn't that the child process couldn't open the mutex, but that it couldn't run at all? – Harry Johnston Dec 16 '15 at 22:06