title: CreateProcessWithLogonW, to create process as another user on different desktop, fails with browser
body: <p><em>First of all it's hard to find a sophisticated title, because the whole situation is complicated and confusing.</em></p>
  
  <p>I'm trying to create a Process as a user with restricted rights (user is part of the "Users"-group). The process should spawn on another desktop(let's name it "test"), not on the <code>"default"</code>-desktop. The process which uses the <code>CreateProcessWithLogonW</code> function is running with admin rights. While a normal application (notepad, vlc, winrar) runs without a problem, browser applications like IE, Firefox, Chrome seem to have a problem. The were started but they're instantly closing without an errorcode. If I'm using a user with administration rights every application runs without an error.</p>
  
  <p>I'm adding ACEs to the winstation and desktop's DACL. Also if I start <code>cmd.exe</code> like this and try to run <code>firefox</code>the same problem occurs. I'm using python 2.7 with ctypes and win32api:</p>
  
  <pre><code>from _ctypes import Array, POINTER, sizeof, byref
  from ctypes import wintypes, windll, WinError
  import ctypes
  from ctypes.wintypes import BYTE, HANDLE, DWORD, BOOL, LPCWSTR, LPWSTR, LPVOID
  
  from win32con import CREATE_NEW_CONSOLE, READ_CONTROL, WRITE_DAC, \
  GROUP_SECURITY_INFORMATION, DESKTOP_WRITEOBJECTS, DESKTOP_READOBJECTS
  import win32con
  from win32security import ACL_REVISION_DS
  import win32security
  import win32service
  
  
  WINSTA_ALL = (win32con.WINSTA_ACCESSCLIPBOARD  | win32con.WINSTA_ACCESSGLOBALATOMS | \
  win32con.WINSTA_CREATEDESKTOP    | win32con.WINSTA_ENUMDESKTOPS      |\
  win32con.WINSTA_ENUMERATE        | win32con.WINSTA_EXITWINDOWS       |\
  win32con.WINSTA_READATTRIBUTES   | win32con.WINSTA_READSCREEN        |\
  win32con.WINSTA_WRITEATTRIBUTES  | win32con.DELETE                   |\
  win32con.READ_CONTROL            | win32con.WRITE_DAC                |\
  win32con.WRITE_OWNER)
  
  DESKTOP_ALL = (win32con.DESKTOP_CREATEMENU      | win32con.DESKTOP_CREATEWINDOW  |\
  win32con.DESKTOP_ENUMERATE       | win32con.DESKTOP_HOOKCONTROL   |\
  win32con.DESKTOP_JOURNALPLAYBACK | win32con.DESKTOP_JOURNALRECORD |\
  win32con.DESKTOP_READOBJECTS     | win32con.DESKTOP_SWITCHDESKTOP |\
  win32con.DESKTOP_WRITEOBJECTS    | win32con.DELETE                |\
  win32con.READ_CONTROL            | win32con.WRITE_DAC             |\
  win32con.WRITE_OWNER)
  
  
  GENERIC_ACCESS =  (win32con.GENERIC_READ    | win32con.GENERIC_WRITE |\
  win32con.GENERIC_EXECUTE | win32con.GENERIC_ALL)
  
  
  
  INVALID_HANDLE_VALUE = -1
  CREATE_UNICODE_ENVIRONMENT = 0x00000400
  
  CData = Array.__base__
  LPBYTE = POINTER(BYTE)
  
  class PROCESS_INFORMATION(ctypes.Structure):
      _fields_ = [
          ('hProcess',    HANDLE),
          ('hThread',     HANDLE),
          ('dwProcessId', DWORD),
          ('dwThreadId',  DWORD),
      ]
  LPPROCESS_INFORMATION = POINTER(PROCESS_INFORMATION)
  
  
  class STARTUPINFOW(ctypes.Structure):
      _fields_ = (('cb',              wintypes.DWORD),
                  ('lpReserved',      wintypes.LPWSTR),
                  ('lpDesktop',       wintypes.LPWSTR),
                  ('lpTitle',         wintypes.LPWSTR),
                  ('dwX',             wintypes.DWORD),
                  ('dwY',             wintypes.DWORD),
                  ('dwXSize',         wintypes.DWORD),
                  ('dwYSize',         wintypes.DWORD),
                  ('dwXCountChars',   wintypes.DWORD),
                  ('dwYCountChars',   wintypes.DWORD),
                  ('dwFillAttribute', wintypes.DWORD),
                  ('dwFlags',         wintypes.DWORD),
                  ('wShowWindow',     wintypes.WORD),
                  ('cbReserved2',     wintypes.WORD),
                  ('lpReserved2',     LPBYTE),
                  ('hStdInput',       wintypes.HANDLE),
                  ('hStdOutput',      wintypes.HANDLE),
                  ('hStdError',       wintypes.HANDLE))
  
  LPSTARTUPINFOW = POINTER(STARTUPINFOW)
  
  
  windll.advapi32.CreateProcessWithLogonW.restype = BOOL
  windll.advapi32.CreateProcessWithLogonW.argtypes = [
      LPCWSTR, # lpUsername
      LPCWSTR, # lpDomain
      LPCWSTR, # lpPassword
      DWORD,   # dwLogonFlags
      LPCWSTR, # lpApplicationName
      LPWSTR,  # lpCommandLine (inout)
      DWORD,   # dwCreationFlags
      LPVOID, # lpEnvironment  (force Unicode)
      LPCWSTR, # lpCurrentDirectory
      LPSTARTUPINFOW, # lpStartupInfo
      LPPROCESS_INFORMATION, # lpProcessInfo (out)
  ]
  
  def CreateProcessWithLogonW(
      lpUsername=None, 
      lpDomain=None, 
      lpPassword=None, 
      dwLogonFlags=0, 
      lpApplicationName=0, 
      lpCommandLine=None,
      dwCreationFlags=0, 
      lpEnvironment=None, 
      lpCurrentDirectory=None,
      startupInfo=None):
  
      if (lpCommandLine is not None and not isinstance(lpCommandLine, CData)):
          lpCommandLine = ctypes.create_unicode_buffer(lpCommandLine)
  
      dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT     
  
      if startupInfo is None:
          startupInfo = STARTUPINFOW(sizeof(STARTUPINFOW))
  
      processInformation = PROCESS_INFORMATION(INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE)
  
      success = windll.advapi32.CreateProcessWithLogonW(
          lpUsername, lpDomain, lpPassword, dwLogonFlags, lpApplicationName,
          lpCommandLine, dwCreationFlags, lpEnvironment, lpCurrentDirectory, 
          byref(startupInfo), byref(processInformation))
  
      if not success:
          raise WinError()
      return processInformation
  
  
  if __name__ == '__main__':
  
      user_group_sid = win32security.LookupAccountName('','Users')[0]
  
      #
      #Adding rights for user group "users" to winsta0
      #
      #getting winsta0 handle
      hwinsta = win32service.OpenWindowStation("winsta0",False,READ_CONTROL | WRITE_DAC )
      #getting security descriptor by winsta0-handle
      sec_desc_winsta = win32security.GetUserObjectSecurity(hwinsta,win32security.OWNER_SECURITY_INFORMATION |win32security.DACL_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION)
      #getting DACL from security descriptor
      dacl_winsta = sec_desc_winsta.GetSecurityDescriptorDacl()
      if dacl_winsta is None:
          #create DACL if not exisiting
          dacl_winsta=win32security.ACL()
      #Adding ACEs to DACL for specific user group
      dacl_winsta.AddAccessAllowedAce(ACL_REVISION_DS,GENERIC_ACCESS,user_group_sid)
      dacl_winsta.AddAccessAllowedAce(ACL_REVISION_DS,WINSTA_ALL,user_group_sid)
      #setting modified DACL for winsta0
      win32security.SetSecurityInfo(hwinsta, win32security.SE_WINDOW_OBJECT,win32security.DACL_SECURITY_INFORMATION,None,None,dacl_winsta,None)
  
      #
      #Adding rights for user group "users" to desktop
      #
      #getting handle of different Desktop
      hdesk = win32service.OpenDesktop("test",0 ,False,READ_CONTROL | WRITE_DAC |DESKTOP_WRITEOBJECTS | DESKTOP_READOBJECTS)
      #getting security descriptor by desktop-handle
      sec_desc_desk = win32security.GetUserObjectSecurity(hdesk,win32security.OWNER_SECURITY_INFORMATION |win32security.DACL_SECURITY_INFORMATION|GROUP_SECURITY_INFORMATION )
      #getting DACL from security descriptor
      dacl_desk = sec_desc_desk.GetSecurityDescriptorDacl()
      if dacl_desk is None:
          #create DACL if not exisiting
          dacl_desk=win32security.ACL()
      #Adding ACEs to DACL for specific user group
      dacl_desk.AddAccessAllowedAce(ACL_REVISION_DS,GENERIC_ACCESS,user_group_sid)
      dacl_desk.AddAccessAllowedAce(ACL_REVISION_DS,DESKTOP_ALL,user_group_sid)
      #setting modified DACL for desktop
      win32security.SetSecurityInfo(hdesk, win32security.SE_WINDOW_OBJECT,win32security.DACL_SECURITY_INFORMATION,None,None,dacl_desk,None)
  
      firefox = "C:\\Program Files (x86)\\Mozilla Firefox\\firefox.exe"
      notepad = "C:\\windows\\notepad.exe"
  
      si = STARTUPINFOW()
      si.lpDesktop = "winsta0\\test"
  
      pi = CreateProcessWithLogonW("test", 
                                  ".", 
                                  "password",
                                  0x00000001,
                                  None,
                                  firefox,
                                  CREATE_NEW_CONSOLE,
                                  startupInfo=si)
  </code></pre>
  
  <p>The weird thing is, if I'm switching to the "test"-desktop and using <code>ShellRunas</code> (shift+right-click -> run as different user) it works perfectly. So it seems like I'm missing to grant my user some rights, but I don't know which rights.</p>
  
  <p>So here are my questions:</p>
  
  <ol>
  <li>Do I use <code>CreateProccesWithLogonW</code> correctly for my purpose?</li>
  <li>What's the difference between <code>CreateProccesWithLogonW</code> and <code>Shellrunas</code>?</li>
  <li>How does <code>Shellrunas</code> works behind the scene?</li>
  </ol>