title: Debugging ERROR_ACCESS_DENIED on Windows API (CreateProcessAsUser)
body: <p>I'm using the JNA to call <a href="https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessasuserw" rel="nofollow noreferrer"><code>CreateProcessAsUserW</code></a> from the Windows API. I'm passing a simple command to <a href="https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessasuserw" rel="nofollow noreferrer"><code>CreateProcessAsUserW</code></a>:</p>
  <pre><code>C:\Windows\System32\cmd.exe /c C:\Windows\SysWOW64\whoami.exe &gt; whoami.txt
  </code></pre>
  <p>Basically, it should print the current user (obtained through <code>whoami.exe</code>) to a file called <code>whoami.txt</code>.
  <strong>It succeeds in this.</strong> After executing my Java program, I see a new file <code>whoami.txt</code> containing my username.</p>
  <p>However, I print the return value of <a href="https://docs.microsoft.com/en-us/windows/win32/api/errhandlingapi/nf-errhandlingapi-getlasterror" rel="nofollow noreferrer"><code>GetLastError</code></a> and see that the error code goes from <code>0</code> to <code>5</code> immediately after calling <a href="https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessasuserw" rel="nofollow noreferrer"><code>CreateProcessAsUserW</code></a>. The <a href="https://docs.microsoft.com/en-us/windows/win32/debug/system-error-codes--0-499-" rel="nofollow noreferrer">System Error Codes</a> says that <code>5</code> is the <code>ERROR_ACCESS_DENIED</code> error.</p>
  <p>I ran the Java process from the Command Prompt running as Administrator. It's worth noting that I'm not switching users when calling <a href="https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/nf-processthreadsapi-createprocessasuserw" rel="nofollow noreferrer"><code>CreateProcessAsUserW</code></a>.</p>
  <p>My hunch is that one of the many arguments to this function is causing a superficial permission error that gets handled gracefully. However, it could also be that I'm missing some user right.</p>
  <p>I'm new to Windows and unfamiliar with better ways to debug such an error. What tools would you all recommend for getting more information about the access denied error? On Linux, <code>journalctl</code> would be of great help here.</p>
  <p>Here is my code:</p>
  <pre class="lang-java prettyprint-override"><code>// https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-startupinfow
  final STARTUPINFOW.ByReference startupInfoW =
      new STARTUPINFOW.ByReference();
  startupInfoW.cb = startupInfoW.size();
  startupInfoW.lpReserved = Pointer.NULL;
  startupInfoW.lpDesktop = Pointer.NULL;
  startupInfoW.lpTitle = Pointer.NULL;
  startupInfoW.dwFlags
      = startupInfoW.dwX = startupInfoW.dwY
      = startupInfoW.dwXSize = startupInfoW.dwYSize
      = startupInfoW.dwXCountChars = startupInfoW.dwYCountChars
      = startupInfoW.dwFillAttribute
      = startupInfoW.wShowWindow
      = 0;
  startupInfoW.cbReserved2  = 0;
  startupInfoW.lpReserved2 = Pointer.NULL;
  startupInfoW.hStdInput = startupInfoW.hStdOutput
      = startupInfoW.hStdError
      = Pointer.NULL;
  // https://docs.microsoft.com/en-us/windows/win32/api/processthreadsapi/ns-processthreadsapi-process_information
  final PROCESS_INFORMATION.ByReference processInformation =
      new PROCESS_INFORMATION.ByReference();
  processInformation.hProcess = processInformation.hThread
      = Pointer.NULL;
  processInformation.dwProcessId = processInformation.dwThreadId
      = 0;
  // Converts string to char array with 0 as last element.
  final char[] whoamiCmd = toCString(
      &quot;C:\\Windows\\System32\\cmd.exe /c C:\\Windows\\SysWOW64\\whoami.exe &gt; whoami.txt&quot;
  );
  System.out.printf(
      &quot;last err code = %d\n&quot;,
      ErrHandlingApi.INSTANCE.GetLastError()
  );
  final boolean createProcessOk = MyProcessThreadsApi.INSTANCE
      .CreateProcessAsUserW(
          userPrimaryToken.getValue(),
          Pointer.NULL,
          whoamiCmd,
          Pointer.NULL,
          Pointer.NULL,
          false,
          WinBase.CREATE_UNICODE_ENVIRONMENT,
          new PointerByReference(),
          Pointer.NULL,
          startupInfoW,
          processInformation
      );
  System.out.printf(
      &quot;last err code = %d\n&quot;,
      ErrHandlingApi.INSTANCE.GetLastError()
  );
  System.out.printf(&quot;ok = %b\n&quot;, createProcessOk);
  System.out.printf(
      &quot;dwProcessId = %d\n&quot;, processInformation.dwProcessId
  );
  </code></pre>
  <pre class="lang-java prettyprint-override"><code>public static char[] toCString(final String str) {
      final char[] cString = new char[str.length() + 1];
      for (int i = 0; i &lt; str.length(); i++) {
          cString[i] = str.charAt(i);
      }
      // c-strings end in 0 for lack of bounds checking
      cString[cString.length-1] = 0;
      return cString;
  }
  </code></pre>
  <pre><code>C:\Users\zjoseal\Desktop&gt;whoami
  ant\zjoseal
  
  C:\Users\zjoseal\Desktop&gt;java -cp windows-credentials-poc-1.0-SNAPSHOT.jar Main
  ...
  last err code = 0
  last err code = 5
  ok = true
  dwProcessId = 6628
  
  C:\Users\zjoseal\Desktop&gt;type whoami.txt
  ant\zjoseal
  
  </code></pre>
  <h2>Edits to Code 1</h2>
  <p>Some of you asked whether the toCString method could be responsible for the error code changing. It just copies the contents of a string to a <code>char[]</code> with and appended a <code>0</code> to make it a null-terminated c-string. I moved it before the first print statement to guarantee that it's not  responsible for the error code.</p>
  <p>Someone also pointed out that the print statement could mess up the error code, so I made sure that the GetLastError call happens immediately after the CreateProcessAsUserW call.</p>