locked
Why CreateProcessAsUser fail on Vista? RRS feed

  • Question

  • Following is the code segment

     if ( !CreateProcessAsUser(
      hToken,// obtained from LogonUser
      NULL,
      ( char * )pszCmd,  
      NULL,
      NULL,
      FALSE,
      dwCreationFlag,
      pEnv,//obtained from CreateEnvironmentBlock
      NULL,
      &si,
      &pi
      ) )
     {
      //error;
     }

    GetLastError gives error code 183

    Tuesday, August 1, 2006 9:31 AM

All replies

  • I have the same when using CreateProcessAsUser it failed with error 183
    Did you solve the issue - where it come from ?

     

    Friday, November 3, 2006 5:23 PM
  • Can I have a little context (or more code)?
    Is that code executing from within a service?

    Note that the token returned by LogonUser will not have have administrative privileges.

    Tuesday, November 7, 2006 4:08 AM
  • BOOL StartSDProcess(CString csProcessPath, CString csCommandLineParam)
    {
    // WritePrivateProfileString("Info","10","start >> " + csProcessPath,CSystemInfo::m_strAppPath + "info.ini");
     OutputDebugString("Start SD Process");
     HANDLE    hToken = NULL;
     TOKEN_USER          oUser[16];
     DWORD               u32Needed;
     TCHAR               sUserName[256], domainName[256];
     DWORD               userNameSize, domainNameSize;
     SID_NAME_USE        sidType;

     ZeroMemory(oUser,sizeof(oUser));

     OpenProcessToken(GetExplorerProcessHandle(), TOKEN_ALL_ACCESS, &hToken);

     OutputDebugString("get exp token");
     if(hToken == NULL)
      return FALSE;

     GetTokenInformation(hToken,TokenUser,&oUser[0], sizeof(oUser), &u32Needed);
     userNameSize     = sizeof (sUserName) - 1;
     domainNameSize     = sizeof (domainName) - 1;
     
     LookupAccountSid (NULL, oUser[0].User.Sid, sUserName, &userNameSize, domainName, &domainNameSize, &sidType);
     HDESK       hdesk = NULL;
     HWINSTA     hwinsta = NULL, hwinstaSave = NULL;
     PROCESS_INFORMATION pi;
     PSID pSid = NULL;
     STARTUPINFO si;
     BOOL bResult = FALSE;
     CString csErr;

     OutputDebugString("GetProcessWindowStation");
    // Save a handle to the caller's current window station.
       if ( (hwinstaSave = GetProcessWindowStation() ) == NULL)
     {
      CloseHandle(hToken); 
      return FALSE;
     }

     
    // Get a handle to the interactive window station.
     hwinsta = OpenWindowStation(
           "winsta0",                   // the interactive window station
           FALSE,                       // handle is not inheritable
           READ_CONTROL | WRITE_DAC);   // rights to read/write the DACL

     OutputDebugString("OpenWindowStation");
     if (hwinsta == NULL)
     {
      SetProcessWindowStation (hwinstaSave);
      CloseHandle(hToken); 
      return FALSE;
     }

    // To get the correct default desktop, set the caller's
    // window station to the interactive window station.

     OutputDebugString("SetProcessWindowStation");
     if (!SetProcessWindowStation(hwinsta))
     {
      SetProcessWindowStation (hwinstaSave);
      CloseWindowStation(hwinsta);
      CloseHandle(hToken); 
      return FALSE;
     }

    // Get a handle to the interactive desktop.

     hdesk = OpenDesktop(
          "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);

     OutputDebugString("OpenDesktop");
     if (hdesk == NULL)
     {
      SetProcessWindowStation (hwinstaSave);
      CloseWindowStation(hwinsta);
      CloseHandle(hToken); 
      return FALSE;
     }

     OutputDebugString("SetProcessWindowStation");
    // Restore the caller's window station.
     if (!SetProcessWindowStation(hwinstaSave))
     {
      
      SetProcessWindowStation (hwinstaSave);
      CloseWindowStation(hwinsta);
      CloseDesktop(hdesk);
      CloseHandle(hToken); 
      return FALSE;
     }

    // Impersonate client to ensure access to executable file.

     OutputDebugString("ImpersonateLoggedOnUser");
     if (! ImpersonateLoggedOnUser(hToken) )
     {
      SetProcessWindowStation (hwinstaSave);
      CloseWindowStation(hwinsta);
      CloseDesktop(hdesk);
      CloseHandle(hToken);
      return FALSE;
     }

    // Initialize the STARTUPINFO structure.
    // Specify that the process runs in the interactive desktop.
       ZeroMemory(&si, sizeof(STARTUPINFO));
       si.cb= sizeof(STARTUPINFO);
       si.lpDesktop = TEXT("winsta0\\default");
       
       char   csCmdParam[MAX_PATH];
       DWORD  dwSize = MAX_PATH;
       strcpy(csCmdParam, csCommandLineParam);
       OutputDebugString("CreateProcessAsUser");
       bResult = CreateProcessAsUser(
          hToken,            // client's access token
          csProcessPath,     // file to execute
       csCmdParam,   // command line
          NULL,              // pointer to process SECURITY_ATTRIBUTES
          NULL,              // pointer to thread SECURITY_ATTRIBUTES
          FALSE,             // handles are not inheritable
          NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE,   // 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(!bResult)
     {
      DWORD dw = GetLastError();
      CString csStr;
      csStr.Format("CreateProcessAsUser failed %d",dw);
      OutputDebugString(csStr);
     }

       SetProcessWindowStation (hwinstaSave);
       CloseWindowStation(hwinsta);
       CloseDesktop(hdesk);
       CloseHandle(hToken);
       // End impersonation of client.

       RevertToSelf();
       return bResult ;
    }

    Tuesday, November 21, 2006 11:02 AM
  • Dipa's solution will work if you want the currently logged on user to run the process.  But if I understand your question that you want another user account other than the currently logged on user, hence why you call LogonUser, (maybe with a restricted account) then there are a list of things you need to do.

    There are examples of how to do this on msdn, but mainly you have to do exactly what is stated above but from the stand point of assigning the token to the desktop and ImpersonateLoggedOnUser.  But you should also Call LoadUserProfile, between LogonUser and ImpersonateLoggedOnUser, so that the user's profile is loaded and registry openned accordingly for that user's key.  Also you need to load the Environment for that specific user by calling CreateEnvironmentBlock with the token of the LogonUser.  Pass this into your CreateProcess and set the UNICODE flag in the dwCreationFlags.

    Also user that is calling all these things must be an administrator or local system because they are the one's that have the granted rights to make such calls.

     

    Hope this helps.

    Tuesday, November 21, 2006 5:24 PM
  • I have code that launches my application from a service that works on XP SP2. I have a call to NetUserGetInfo(NULL,username,4, (LPBYTE*) &userInfo4) and then LoadUserProfile.

    My problem is that userInfo4.usri4_profile is NULL, as are all the fields except usri4_name.

    Is there some other way that I can LoadUserProfile?

     

     

    My full code is as follows:

     

      DWORD sessionId = WTSGetActiveConsoleSessionId();
      HANDLE hToken;
      if (!WTSQueryUserToken(sessionId, &hToken))
      {
       // need Query Information permission
       ReportError(_T("WTSQueryUserToken failed"));
       return;
      }

      LPVOID environment = NULL;
      if (!CreateEnvironmentBlock (&environment, hToken, FALSE))
      {
       ReportError(_T("Unable to CreateEnvironmentBlock."));
       return;
      }

      LPTSTR username;
      DWORD size = 0;
      if (!WTSQuerySessionInformation (WTS_CURRENT_SERVER_HANDLE, sessionId, WTSUserName, &username, &size))
      {
       ReportError(_T("Unable to WTSQuerySessionInformation."));
       return;
      }

      USER_INFO_4 userInfo4;
      ZeroMemory (&userInfo4, sizeof (userInfo4));
      if (NERR_Success != NetUserGetInfo (NULL, username, 4, (LPBYTE*) &userInfo4))
      {
       ReportError (_T("NetUserGetInfo failed"));
       return;
      }
      else if (userInfo4.usri4_profile == NULL)
      {
       WriteToLog (_T("NetUserGetInfo failed to get usri4_profile"));
       return;
      }

      PROFILEINFO profileInfo;
      memset (&profileInfo, 0 , sizeof(profileInfo));
      profileInfo.dwSize = sizeof(profileInfo);
      profileInfo.lpUserName = username;
      profileInfo.lpProfilePath = userInfo4.usri4_profile;              // <---------- this is NULL under Vista (RTM)
      if (!LoadUserProfile (hToken, &profileInfo))
      {
       ReportError(_T("Unable to LoadUserProfile."));
       return;
      }

      WTSFreeMemory (username);

      if ( !::CreateProcessAsUser(
        hToken,
        NULL,    // program
        controlCenterPath,  // command line
        NULL,    // process handle not inheritable
        NULL,    // thread handle not inheritable
        FALSE,    // set handle inheritance to false
        CREATE_UNICODE_ENVIRONMENT,  // creation flags
        environment,  // environment block
        NULL,    // use parent's starting directory
        &si,    // address to startup info
        &pi))    // address to process information
      {
       ReportError(_T("Unable to launch Control Center as user."));
       WriteToLog(controlCenterPath);
      }
      UnloadUserProfile (hToken, profileInfo.hProfile);
      if (environment != NULL)
       DestroyEnvironmentBlock (environment);
      NetApiBufferFree (&userInfo4);
      CloseHandle (hToken);

    Friday, December 8, 2006 6:51 PM
  • The profile of logged on users is already loaded by winlogon.
    You don't need to do this yourself.

    And by the way, if you had to, you'd want to call CreateEnvironmentBlock *after* you've loaded the profile...

    Monday, December 11, 2006 9:10 PM
  • Event if the user is an Administartor? So what do you suggest one should do to use that token with CreateProcessAsUser() on vista. I'm having problem where CreateProcessAsUser() fails with 193 when called from LocalSystem service.

    Wednesday, May 6, 2009 11:11 PM