Index: /trunk/include/iprt/err.h
===================================================================
--- /trunk/include/iprt/err.h	(revision 57905)
+++ /trunk/include/iprt/err.h	(revision 57906)
@@ -937,4 +937,18 @@
 /** Wrong type. */
 #define VERR_WRONG_TYPE                     (-22409)
+/** This indicates that the process does not have sufficient privileges to
+ * perform the operation. */
+#define VERR_PRIVILEGE_NOT_HELD             (-22410)
+/** Process does not have the trusted code base (TCB) privilege needed for user
+ * authentication or/and process creation as a given user.  TCB is also called
+ * 'Act as part of the operating system'. */
+#define VERR_PROC_TCB_PRIV_NOT_HELD         (-22411)
+/** Process does not have the assign primary token (APT) privilege needed
+ * for creating process as a given user.  APT is also called 'Replace a process
+ * level token'. */
+#define VERR_PROC_APT_PRIV_NOT_HELD         (-22412)
+/** Process does not have the increase quota (IQ) privilege needed for
+ * creating a process as a given user. IQ is also called 'Increase quotas'. */
+#define VERR_PROC_IQ_PRIV_NOT_HELD          (-22413)
 /** @} */
 
Index: /trunk/src/VBox/Runtime/r3/win/process-win.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/win/process-win.cpp	(revision 57905)
+++ /trunk/src/VBox/Runtime/r3/win/process-win.cpp	(revision 57906)
@@ -32,6 +32,6 @@
 #include <iprt/asm.h> /* hack */
 
+#include <iprt/nt/nt-and-windows.h>
 #include <Userenv.h>
-#include <Windows.h>
 #include <tlhelp32.h>
 #include <process.h>
@@ -136,4 +136,6 @@
 *********************************************************************************************************************************/
 static int rtProcWinFindExe(uint32_t fFlags, RTENV hEnv, const char *pszExec, PRTUTF16 *ppwszExec);
+static int rtProcWinCreateEnvBlockAndFindExe(uint32_t fFlags, RTENV hEnv, const char *pszExec,
+                                             PRTUTF16 *ppwszzBlock, PRTUTF16 *ppwszExec);
 
 
@@ -369,22 +371,6 @@
     switch (dwError)
     {
-        case ERROR_NOACCESS:
-        case ERROR_PRIVILEGE_NOT_HELD:
+        case ERROR_NOACCESS: /** @todo r=bird: this is a bogus transation.  Used a couple of places in main. */
             rc = VERR_PERMISSION_DENIED;
-            break;
-
-        case ERROR_PASSWORD_EXPIRED:
-        case ERROR_ACCOUNT_RESTRICTION: /* See: http://support.microsoft.com/kb/303846/ */
-        case ERROR_PASSWORD_RESTRICTION:
-        case ERROR_ACCOUNT_DISABLED:    /* See: http://support.microsoft.com/kb/263936 */
-            rc = VERR_ACCOUNT_RESTRICTED;
-            break;
-
-        case ERROR_FILE_CORRUPT:
-            rc = VERR_BAD_EXE_FORMAT;
-            break;
-
-        case ERROR_BAD_DEVICE: /* Can happen when opening funny things like "CON". */
-            rc = VERR_INVALID_NAME;
             break;
 
@@ -660,7 +646,11 @@
      * for NULL domain names when running on NT4 here, pass an empty string if so.
      * However, passing FQDNs should work!
-     */
+     *
+     * The SE_TCB_NAME (Policy: Act as part of the operating system) right
+     * is required on older windows versions (NT4, W2K, possibly XP).
+     */
+    PCRTUTF16 pwszDomainToUse = g_enmWinVer < kRTWinOSType_2K ? L"" /* NT4 and older */ : NULL /* Windows 2000 and up */;
     BOOL fRc = LogonUserW(pwszUser,
-                          g_enmWinVer < kRTWinOSType_2K ? L"" /* NT4 and older */ : NULL /* Windows 2000 and up */,
+                          pwszDomainToUse,
                           pwszPassword,
                           LOGON32_LOGON_INTERACTIVE,
@@ -671,5 +661,5 @@
 
     DWORD dwErr = GetLastError();
-    int rc = rtProcWinMapErrorCodes(dwErr);
+    int rc = dwErr == ERROR_PRIVILEGE_NOT_HELD ? VERR_PROC_TCB_PRIV_NOT_HELD : rtProcWinMapErrorCodes(dwErr);
     if (rc == VERR_UNRESOLVED_ERROR)
         LogRelFunc(("dwErr=%u (%#x), rc=%Rrc\n", dwErr, dwErr, rc));
@@ -751,4 +741,56 @@
 
     return rc;
+}
+
+
+/**
+ * Figures which privilege we're missing for success application of
+ * CreateProcessAsUserW.
+ *
+ * @returns IPRT error status.
+ */
+static int rtProcWinFigureWhichPrivilegeNotHeld2(void)
+{
+    HANDLE hToken;
+    if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES, &hToken))
+    {
+        static struct
+        {
+            const char *pszName;
+            int         rc;
+        } const s_aPrivileges[] =
+        {
+            { SE_TCB_NAME,                      VERR_PROC_TCB_PRIV_NOT_HELD },
+            { SE_ASSIGNPRIMARYTOKEN_NAME,       VERR_PROC_APT_PRIV_NOT_HELD },
+            { SE_INCREASE_QUOTA_NAME,           VERR_PROC_IQ_PRIV_NOT_HELD  },
+        };
+        for (uint32_t i = 0; i < RT_ELEMENTS(s_aPrivileges); i++)
+        {
+            union
+            {
+                TOKEN_PRIVILEGES TokPriv;
+                char abAlloced[sizeof(TOKEN_PRIVILEGES) + sizeof(LUID_AND_ATTRIBUTES)];
+            } uNew, uOld;
+            uNew.TokPriv.PrivilegeCount = 1;
+            uNew.TokPriv.Privileges[0].Attributes = SE_PRIVILEGE_ENABLED;
+            AssertStmt(LookupPrivilegeValue(NULL, s_aPrivileges[i].pszName, &uNew.TokPriv.Privileges[0].Luid), continue);
+            uOld = uNew;
+            SetLastError(NO_ERROR);
+            DWORD cbActual = RT_OFFSETOF(TOKEN_PRIVILEGES, Privileges[1]);
+            AdjustTokenPrivileges(hToken, FALSE /*fDisableAllPrivileges*/, &uNew.TokPriv, cbActual, &uOld.TokPriv, &cbActual);
+            if (GetLastError() != NO_ERROR)
+            {
+                CloseHandle(hToken);
+                return s_aPrivileges[i].rc;
+            }
+            if (uOld.TokPriv.Privileges[0].Attributes == 0)
+                AdjustTokenPrivileges(hToken, FALSE /*fDisableAllPrivileges*/, &uOld.TokPriv, 0, NULL, NULL);
+        }
+        AssertFailed();
+        CloseHandle(hToken);
+    }
+    else
+        AssertFailed();
+    return VERR_PRIVILEGE_NOT_HELD;
 }
 
@@ -782,11 +824,10 @@
      * The following rights are needed in order to use LogonUserW and
      * CreateProcessAsUserW, so the local policy has to be modified to:
-     *  - SE_TCB_NAME = Act as part of the operating system
-     *  - SE_ASSIGNPRIMARYTOKEN_NAME = Create/replace a token object
-     *  - SE_INCREASE_QUOTA_NAME
+     *  - SE_TCB_NAME                = Act as part of the operating system
+     *  - SE_ASSIGNPRIMARYTOKEN_NAME = Create/replace a (process) token object
+     *  - SE_INCREASE_QUOTA_NAME     = Increase quotas
      *
      * We may fail here with ERROR_PRIVILEGE_NOT_HELD.
      */
-/** @todo r=bird: Both methods starts with rtProcWinUserLogon, so we could probably do that once in the parent function, right... */
     DWORD   dwErr       = NO_ERROR;
     HANDLE  hTokenLogon = INVALID_HANDLE_VALUE;
@@ -831,5 +872,8 @@
                     }
                     else
-                        dwErr = GetLastError() != NO_ERROR ? GetLastError() : ERROR_INTERNAL_ERROR;
+                    {
+                        dwErr = GetLastError();
+                        rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_3;
+                    }
                     RTMemFree(pwszDomain);
                 }
@@ -844,5 +888,5 @@
         /* If we got an error due to account lookup/loading above, don't
          * continue here. */
-        if (dwErr == NO_ERROR)
+        if (RT_SUCCESS(rc))
         {
             /*
@@ -868,7 +912,7 @@
 
                     if (!g_pfnLoadUserProfileW(hTokenToUse, &ProfileInfo))
-                        dwErr = GetLastError();
+                        rc = RTErrConvertFromWin32(GetLastError());
                 }
-                if (dwErr == NO_ERROR)
+                if (RT_SUCCESS(rc))
                 {
                     /*
@@ -906,7 +950,13 @@
                                                            pProcInfo);
                                 if (fRc)
-                                    dwErr = NO_ERROR;
+                                    rc = VINF_SUCCESS;
                                 else
-                                    dwErr = GetLastError(); /* CreateProcessAsUserW() failed. */
+                                {
+                                    dwErr = GetLastError();
+                                    if (dwErr == ERROR_PRIVILEGE_NOT_HELD)
+                                        rc = rtProcWinFigureWhichPrivilegeNotHeld2();
+                                    else
+                                        rc = RTErrConvertFromWin32(dwErr);
+                                }
                             }
                             RTEnvFreeUtf16Block(pwszzBlock);
@@ -939,14 +989,6 @@
         CloseHandle(hTokenLogon);
 
-        /*
-         * Do error conversion.
-         */
-        if (   RT_SUCCESS(rc)
-            && dwErr != NO_ERROR)
-        {
-            rc = rtProcWinMapErrorCodes(dwErr);
-            if (rc == VERR_UNRESOLVED_ERROR)
-                LogRelFunc(("dwErr=%u (%#x), rc=%Rrc\n", dwErr, dwErr, rc));
-        }
+        if (rc == VERR_UNRESOLVED_ERROR)
+            LogRelFunc(("dwErr=%u (%#x), rc=%Rrc\n", dwErr, dwErr, rc));
     }
     return rc;
@@ -955,9 +997,76 @@
 
 /**
+ * Plants a standard handle into a child process on older windows versions.
+ *
+ * This is only needed when using CreateProcessWithLogonW on older windows
+ * versions.  It would appear that newer versions of windows does this for us.
+ *
+ * @param   hSrcHandle              The source handle.
+ * @param   hDstProcess             The child process handle.
+ * @param   offProcParamMember      The offset to RTL_USER_PROCESS_PARAMETERS.
+ * @param   ppvDstProcParamCache    Where where cached the address of
+ *                                  RTL_USER_PROCESS_PARAMETERS in the child.
+ */
+static void rtProcWinDupStdHandleIntoChild(HANDLE hSrcHandle, HANDLE hDstProcess, uint32_t offProcParamMember,
+                                           PVOID *ppvDstProcParamCache)
+{
+    if (hSrcHandle != NULL && hSrcHandle != INVALID_HANDLE_VALUE)
+    {
+        HANDLE hDstHandle;
+        if (DuplicateHandle(GetCurrentProcess(), hSrcHandle, hDstProcess, &hDstHandle,
+                            0 /*IgnoredDesiredAccess*/, FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS))
+        {
+            if (hSrcHandle == hDstHandle)
+                return;
+
+            if (!*ppvDstProcParamCache)
+            {
+                PROCESS_BASIC_INFORMATION BasicInfo;
+                ULONG cbIgn;
+                NTSTATUS rcNt = NtQueryInformationProcess(hDstProcess, ProcessBasicInformation,
+                                                          &BasicInfo, sizeof(BasicInfo), &cbIgn);
+                if (NT_SUCCESS(rcNt))
+                {
+                    SIZE_T cbCopied = 0;
+                    if (!ReadProcessMemory(hDstProcess,
+                                           (char *)BasicInfo.PebBaseAddress + RT_OFFSETOF(PEB_COMMON, ProcessParameters),
+                                           ppvDstProcParamCache, sizeof(*ppvDstProcParamCache), &cbCopied))
+                    {
+                        AssertMsgFailed(("PebBaseAddress=%p %d\n", BasicInfo.PebBaseAddress, GetLastError()));
+                        *ppvDstProcParamCache = NULL;
+                    }
+                }
+                else
+                    AssertMsgFailed(("rcNt=%#x\n", rcNt));
+            }
+            if (*ppvDstProcParamCache)
+            {
+                if (WriteProcessMemory(hDstProcess, (char *)*ppvDstProcParamCache + offProcParamMember,
+                                       &hDstHandle, sizeof(hDstHandle), NULL))
+                    return;
+            }
+
+            /*
+             * Close the handle.
+             */
+            HANDLE hSrcHandle2;
+            if (DuplicateHandle(hDstProcess, hDstHandle, GetCurrentProcess(), &hSrcHandle2,
+                                0 /*IgnoredDesiredAccess*/, FALSE /*fInherit*/, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE))
+                CloseHandle(hSrcHandle2);
+            else
+                AssertMsgFailed(("hDstHandle=%p %u\n", hDstHandle, GetLastError()));
+        }
+        else
+            AssertMsg(GetLastError() == ERROR_INVALID_PARAMETER, ("%u\n", GetLastError()));
+    }
+}
+
+
+/**
  * Method \#1.
  *
- * This may fail on too old (NT4) platforms or if the calling process
- * is running on a SYSTEM account (like a service, ERROR_ACCESS_DENIED) on newer
- * platforms (however, this works on W2K!).
+ * This method requires Windows 2000 or later.  It may fail if the process is
+ * running under the SYSTEM account (like a service, ERROR_ACCESS_DENIED) on
+ * newer platforms (however, this works on W2K!).
  */
 static int rtProcWinCreateAsUser1(PRTUTF16 pwszUser, PRTUTF16 pwszPassword, PRTUTF16 *ppwszExec, PRTUTF16 pwszCmdLine,
@@ -966,75 +1075,144 @@
                                   uint32_t fFlags, const char *pszExec)
 {
+    /* The CreateProcessWithLogonW API was introduced with W2K and later.  It uses a service
+       for launching the process. */
     if (!g_pfnCreateProcessWithLogonW)
         return VERR_SYMBOL_NOT_FOUND;
 
-    RTENV  hEnvToUse = NIL_RTENV;
-    HANDLE hToken;
-    int rc = rtProcWinUserLogon(pwszUser, pwszPassword, NULL /* Domain */, &hToken);
+    /*
+     * Create the environment block and find the executable first.
+     *
+     * We try to skip this when RTPROC_FLAGS_PROFILE is set so we can sidestep
+     * potential missing TCB privilege issues when calling UserLogonW.  At least
+     * NT4 and W2K requires the trusted code base (TCB) privilege for logon use.
+     * Passing pwszzBlock=NULL and LOGON_WITH_PROFILE means the child process
+     * gets the environment specified by the user profile.
+     */
+    int      rc         = VINF_SUCCESS;
+    PRTUTF16 pwszzBlock = NULL;
+
+    /* Eliminating the path search flags simplifies things a little. */
+    if (   (fFlags & RTPROC_FLAGS_SEARCH_PATH)
+        && (RTPathHasPath(pszExec) || RTPathExists(pszExec)))
+        fFlags &= ~RTPROC_FLAGS_SEARCH_PATH;
+
+    /*
+     * No profile is simple, as is a user specified environment (no change record).
+     */
+    if (   !(fFlags & RTPROC_FLAGS_PROFILE)
+        || (   !(fFlags & RTPROC_FLAGS_ENV_CHANGE_RECORD)
+            && hEnv != RTENV_DEFAULT))
+        rc = rtProcWinCreateEnvBlockAndFindExe(fFlags, hEnv, pszExec, &pwszzBlock, ppwszExec);
+    /*
+     * Default profile environment without changes or path searching we leave
+     * to the service that implements the API.
+     */
+    else if (   hEnv == RTENV_DEFAULT
+             && !(fFlags & (RTPROC_FLAGS_ENV_CHANGE_RECORD | RTPROC_FLAGS_SEARCH_PATH)))
+        pwszzBlock = NULL;
+    /*
+     * Otherwise, we need to get the user profile environment.
+     */
+    else
+    {
+        RTENV  hEnvToUse = NIL_RTENV;
+        HANDLE hToken;
+        rc = rtProcWinUserLogon(pwszUser, pwszPassword, NULL /* Domain */, &hToken);
+        if (RT_SUCCESS(rc))
+        {
+    /** @todo r=bird: Why didn't we load the environment here?  The
+     *       CreateEnvironmentBlock docs indicate that USERPROFILE isn't set
+     *       unless we call LoadUserProfile first.  However, experiments here on W10
+     *       shows it isn't really needed though. Weird.
+     * Update: It works even on W2K. Possible only required for roaming profiles? */
+#if 0
+            if (fFlags & RTPROC_FLAGS_PROFILE)
+            {
+                PROFILEINFOW ProfileInfo;
+                RT_ZERO(ProfileInfo);
+                ProfileInfo.dwSize     = sizeof(ProfileInfo);
+                ProfileInfo.lpUserName = pwszUser;
+                ProfileInfo.dwFlags    = PI_NOUI; /* Prevents the display of profile error messages. */
+
+                if (g_pfnLoadUserProfileW(hToken, &ProfileInfo))
+                {
+                    rc = rtProcWinCreateEnvFromToken(hToken, hEnv, fFlags, &hEnvToUse);
+
+                    if (!g_pfnUnloadUserProfile(hToken, ProfileInfo.hProfile))
+                        AssertFailed();
+                }
+                else
+                    rc = RTErrConvertFromWin32(GetLastError());
+            }
+            else
+#endif
+                rc = rtProcWinCreateEnvFromToken(hToken, hEnv, fFlags, &hEnvToUse);
+            CloseHandle(hToken);
+
+            /*
+             * Query the environment block and find the executable file,
+             * Then destroy any temp env block.
+             */
+            if (RT_SUCCESS(rc))
+            {
+                rc = rtProcWinFindExe(fFlags, hEnv, pszExec, ppwszExec);
+                if (RT_SUCCESS(rc))
+                    rc = RTEnvQueryUtf16Block(hEnvToUse, &pwszzBlock);
+                if (hEnvToUse != hEnv)
+                    RTEnvDestroy(hEnvToUse);
+            }
+        }
+    }
     if (RT_SUCCESS(rc))
     {
-/** @todo r=bird: Why didn't we load the environment here?  The
- *       CreateEnvironmentBlock docs indicate that USERPROFILE isn't set
- *       unless we call LoadUserProfile first.  However, experiments here on W10
- *       shows it isn't really needed though. Weird. */
-#if 0
-        if (fFlags & RTPROC_FLAGS_PROFILE)
-        {
-            PROFILEINFOW ProfileInfo;
-            RT_ZERO(ProfileInfo);
-            ProfileInfo.dwSize     = sizeof(ProfileInfo);
-            ProfileInfo.lpUserName = pwszUser;
-            ProfileInfo.dwFlags    = PI_NOUI; /* Prevents the display of profile error messages. */
-
-            if (g_pfnLoadUserProfileW(hToken, &ProfileInfo))
-            {
-                rc = rtProcWinCreateEnvFromToken(hToken, hEnv, fFlags, &hEnvToUse);
-
-                if (!g_pfnUnloadUserProfile(hToken, ProfileInfo.hProfile))
-                    AssertFailed();
-            }
+        Assert(!(dwCreationFlags & CREATE_SUSPENDED));
+        bool const fCreatedSuspended = g_enmWinVer < kRTWinOSType_XP;
+        BOOL fRc = g_pfnCreateProcessWithLogonW(pwszUser,
+                                                NULL,                       /* lpDomain*/
+                                                pwszPassword,
+                                                fFlags & RTPROC_FLAGS_PROFILE ? 1 /*LOGON_WITH_ PROFILE*/ : 0,
+                                                *ppwszExec,
+                                                pwszCmdLine,
+                                                dwCreationFlags | (fCreatedSuspended ? CREATE_SUSPENDED : 0),
+                                                pwszzBlock,
+                                                NULL,                       /* pCurrentDirectory */
+                                                pStartupInfo,
+                                                pProcInfo);
+        if (fRc)
+        {
+            if (!fCreatedSuspended)
+                rc = VINF_SUCCESS;
             else
-                rc = RTErrConvertFromWin32(GetLastError());
+            {
+                /* Duplicate standard handles into the child process, we ignore failures here as it's
+                   legal to have bad standard handle values and we cannot dup console I/O handles. */
+                PVOID pvDstProcParamCache = NULL;
+                rtProcWinDupStdHandleIntoChild(pStartupInfo->hStdInput, pProcInfo->hProcess,
+                                               RT_OFFSETOF(RTL_USER_PROCESS_PARAMETERS, StandardInput), &pvDstProcParamCache);
+                rtProcWinDupStdHandleIntoChild(pStartupInfo->hStdOutput, pProcInfo->hProcess,
+                                               RT_OFFSETOF(RTL_USER_PROCESS_PARAMETERS, StandardOutput), &pvDstProcParamCache);
+                rtProcWinDupStdHandleIntoChild(pStartupInfo->hStdError,  pProcInfo->hProcess,
+                                               RT_OFFSETOF(RTL_USER_PROCESS_PARAMETERS, StandardError), &pvDstProcParamCache);
+
+                if (ResumeThread(pProcInfo->hThread) == ~(DWORD)0)
+                    rc = RTErrConvertFromWin32(GetLastError());
+                if (RT_FAILURE(rc))
+                {
+                    TerminateProcess(pProcInfo->hProcess, 127);
+                    CloseHandle(pProcInfo->hThread);
+                    CloseHandle(pProcInfo->hProcess);
+                }
+            }
         }
         else
-#endif
-            rc = rtProcWinCreateEnvFromToken(hToken, hEnv, fFlags, &hEnvToUse);
-        CloseHandle(hToken);
-    }
-    if (RT_SUCCESS(rc))
-    {
-        PRTUTF16 pwszzBlock;
-        rc = RTEnvQueryUtf16Block(hEnvToUse, &pwszzBlock);
-        if (RT_SUCCESS(rc))
-        {
-            rc = rtProcWinFindExe(fFlags, hEnv, pszExec, ppwszExec);
-            if (RT_SUCCESS(rc))
-            {
-                BOOL fRc = g_pfnCreateProcessWithLogonW(pwszUser,
-                                                        NULL,                       /* lpDomain*/
-                                                        pwszPassword,
-                                                        fFlags & RTPROC_FLAGS_PROFILE ? 1 /*LOGON_WITH_PROFILE*/ : 0,
-                                                        *ppwszExec,
-                                                        pwszCmdLine,
-                                                        dwCreationFlags,
-                                                        pwszzBlock,
-                                                        NULL,                       /* pCurrentDirectory */
-                                                        pStartupInfo,
-                                                        pProcInfo);
-                if (fRc)
-                    rc = VINF_SUCCESS;
-                else
-                {
-                    DWORD dwErr = GetLastError();
-                    rc = rtProcWinMapErrorCodes(dwErr);
-                    if (rc == VERR_UNRESOLVED_ERROR)
-                        LogRelFunc(("g_pfnCreateProcessWithLogonW (%p) failed: dwErr=%u (%#x), rc=%Rrc\n",
-                                    g_pfnCreateProcessWithLogonW, dwErr, dwErr, rc));
-                }
-            }
+        {
+            DWORD dwErr = GetLastError();
+            rc = rtProcWinMapErrorCodes(dwErr);
+            if (rc == VERR_UNRESOLVED_ERROR)
+                LogRelFunc(("g_pfnCreateProcessWithLogonW (%p) failed: dwErr=%u (%#x), rc=%Rrc\n",
+                            g_pfnCreateProcessWithLogonW, dwErr, dwErr, rc));
+        }
+        if (pwszzBlock)
             RTEnvFreeUtf16Block(pwszzBlock);
-        }
-        if (hEnvToUse != hEnv)
-            RTEnvDestroy(hEnvToUse);
     }
     return rc;
@@ -1049,6 +1227,5 @@
     /*
      * If we run as a service CreateProcessWithLogon will fail, so don't even
-     * try it (because of Local System context).   This method may not work on
-     * older OSes, it will fail and we try the next alternative.
+     * try it (because of Local System context).  This method is very slow on W2K.
      */
     if (!(fFlags & RTPROC_FLAGS_SERVICE))
Index: /trunk/src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp	(revision 57905)
+++ /trunk/src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp	(revision 57906)
@@ -168,5 +168,6 @@
 #if 1
     /* For manual testing. */
-    if (strcmp(argv[2],"noinherit-change-record") == 0)
+    if (strcmp(argv[2],"noinherit") == 0)
+    //if (strcmp(argv[2],"noinherit-change-record") == 0)
     {
         RTENV hEnv;
@@ -230,36 +231,46 @@
     RTTESTI_CHECK_RC_RETV(RTEnvCreateChangeRecord(&hEnvChange), VINF_SUCCESS);
     RTTESTI_CHECK_RC_RETV(RTEnvSetEx(hEnvChange, "testcase-child-6", "changed"), VINF_SUCCESS);
-    RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, hEnvChange, RTPROC_FLAGS_ENV_CHANGE_RECORD,
+    int rc;
+    RTTESTI_CHECK_RC(rc = RTProcCreateEx(g_szExecName, apszArgs, hEnvChange, RTPROC_FLAGS_ENV_CHANGE_RECORD,
                                          NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
-    ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
-    ProcStatus.iStatus   = -1;
-    RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
-
-    if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
-        RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
+    if (RT_SUCCESS(rc))
+    {
+        ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
+        ProcStatus.iStatus   = -1;
+        RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
+
+        if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
+            RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
+    }
 
 
     /* Use profile environment this time. */
     apszArgs[2] = "noinherit";
-    RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, RTPROC_FLAGS_PROFILE,
+    RTTESTI_CHECK_RC(rc = RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, RTPROC_FLAGS_PROFILE,
                                          NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
-    ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
-    ProcStatus.iStatus   = -1;
-    RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
-
-    if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
-        RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
+    if (RT_SUCCESS(rc))
+    {
+        ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
+        ProcStatus.iStatus   = -1;
+        RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
+
+        if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
+            RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
+    }
 
     /* Use profile environment this time. */
     apszArgs[2] = "noinherit-change-record";
-    RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, hEnvChange,
+    RTTESTI_CHECK_RC(rc = RTProcCreateEx(g_szExecName, apszArgs, hEnvChange,
                                          RTPROC_FLAGS_PROFILE | RTPROC_FLAGS_ENV_CHANGE_RECORD,
                                          NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
-    ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
-    ProcStatus.iStatus   = -1;
-    RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
-
-    if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
-        RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
+    if (RT_SUCCESS(rc))
+    {
+        ProcStatus.enmReason = RTPROCEXITREASON_ABEND;
+        ProcStatus.iStatus   = -1;
+        RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
+
+        if (ProcStatus.enmReason != RTPROCEXITREASON_NORMAL || ProcStatus.iStatus != 0)
+            RTTestIFailed("enmReason=%d iStatus=%d", ProcStatus.enmReason, ProcStatus.iStatus);
+    }
 
 
@@ -403,9 +414,12 @@
 
     /* Test for invalid logons. */
-    RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
-                                         NULL, NULL, "non-existing-user", "wrong-password", &hProc), VERR_AUTHENTICATION_FAILURE);
+    int rc = RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL, NULL, NULL,
+                            "non-existing-user", "wrong-password", &hProc);
+    if (rc != VERR_AUTHENTICATION_FAILURE && rc != VERR_PRIVILEGE_NOT_HELD && rc != VERR_PROC_TCB_PRIV_NOT_HELD)
+        RTTestIFailed("rc=%Rrc");
+
     /* Test for invalid application. */
-    RTTESTI_CHECK_RC_RETV(RTProcCreateEx("non-existing-app", apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
-                                         NULL, NULL, NULL, NULL, &hProc), VERR_FILE_NOT_FOUND);
+    RTTESTI_CHECK_RC(RTProcCreateEx("non-existing-app", apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
+                                    NULL, NULL, NULL, NULL, &hProc), VERR_FILE_NOT_FOUND);
     /* Test a (hopefully) valid user/password logon (given by parameters of this function). */
     RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
Index: /trunk/src/VBox/Runtime/win/RTErrConvertFromWin32.cpp
===================================================================
--- /trunk/src/VBox/Runtime/win/RTErrConvertFromWin32.cpp	(revision 57905)
+++ /trunk/src/VBox/Runtime/win/RTErrConvertFromWin32.cpp	(revision 57906)
@@ -148,4 +148,5 @@
 
         case ERROR_INVALID_NAME:
+        case ERROR_BAD_DEVICE:
         case ERROR_BAD_PATHNAME:            return VERR_INVALID_NAME;
 
@@ -184,4 +185,5 @@
         case ERROR_INVALID_EXE_SIGNATURE:   return VERR_INVALID_EXE_SIGNATURE;
         case ERROR_BAD_EXE_FORMAT:          return VERR_BAD_EXE_FORMAT;
+        case ERROR_FILE_CORRUPT:            return VERR_BAD_EXE_FORMAT;
         case ERROR_RESOURCE_DATA_NOT_FOUND: return VERR_NO_DATA; ///@todo fix ERROR_RESOURCE_DATA_NOT_FOUND translation
         case ERROR_INVALID_ADDRESS:         return VERR_INVALID_POINTER; ///@todo fix ERROR_INVALID_ADDRESS translation - dbghelp returns it on some line number queries.
@@ -192,4 +194,11 @@
 
         case ERROR_LOGON_FAILURE:           return VERR_AUTHENTICATION_FAILURE;
+        case ERROR_PRIVILEGE_NOT_HELD:      return VERR_PRIVILEGE_NOT_HELD;
+
+        case ERROR_PASSWORD_EXPIRED:
+        case ERROR_ACCOUNT_RESTRICTION:
+        case ERROR_PASSWORD_RESTRICTION:
+        case ERROR_ACCOUNT_DISABLED:        return VERR_ACCOUNT_RESTRICTED;
+
 
         /*
