Index: /trunk/doc/VBox-CodingGuidelines.cpp
===================================================================
--- /trunk/doc/VBox-CodingGuidelines.cpp	(revision 80568)
+++ /trunk/doc/VBox-CodingGuidelines.cpp	(revision 80569)
@@ -629,4 +629,5 @@
  *                                      NULL,           // pszAsUser
  *                                      NULL,           // pszPassword
+ *                                      NULL,           // pExtraData
  *                                      &hProcess);
  *        @endcode
Index: /trunk/doc/manual/en_US/user_AdvancedTopics.xml
===================================================================
--- /trunk/doc/manual/en_US/user_AdvancedTopics.xml	(revision 80568)
+++ /trunk/doc/manual/en_US/user_AdvancedTopics.xml	(revision 80569)
@@ -5875,4 +5875,58 @@
         <ulink
       url="http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/BPSystemStartup.html">http://developer.apple.com/mac/library/documentation/MacOSX/Conceptual/BPSystemStartup/BPSystemStartup.html</ulink>.
+      </para>
+
+    </sect2>
+
+    <sect2 id="autostart-windows">
+
+      <title>Windows: Starting the Autostart Service With windows service</title>
+
+      <para>
+        On Windows, the autostarting is implemented as Windows service.
+        The service is installed for every user with her/his own credentials.
+        Before installing any autostart services on a system you have to define
+        the <computeroutput>VBOXAUTOSTART_CONFIG</computeroutput> environment
+        variable in the system variables with the path to the config file.
+        The config file has the same format as on Linux,
+        see <xref linkend="autostart-linux" />, except the user name
+        can be specified using following formats: "user", "domain\user",
+        ".\user" and "user@domain".
+      </para>
+
+      <para>
+        To activate the autostart ability for particular user a member of
+        administrators group must run the following command:
+      </para>
+
+      <screen>VBoxAutostartSvc install --user=&lt;user&gt; [--password-file=&lt;password_file&gt;]</screen>
+
+      <para>
+        The password file should contain the password followed by a line break.
+        The rest of the file is ignored. The user will be asked for a password
+        if the password file is not specified.
+      </para>
+
+      <para>
+        To remove the autostart ability for particular user a member of
+        administrators group must run the following command:
+      </para>
+
+      <screen>VBoxAutostartSvc delete --user=&lt;user&gt;</screen>
+
+      <para>
+        The user can be specified for both commands using following formats:
+        "user", "domain\user", ".\user" and "user@domain"
+      </para>
+
+      <para>
+        Note:
+      </para>
+
+      <para>
+        If user has changed his password a member of administrators group
+        must either reinstall the service or change the service credentials
+        using windows service manager. The autostart service can not be
+        installed for users with empty passwords due to Windows security policies.
       </para>
 
Index: /trunk/include/iprt/process.h
===================================================================
--- /trunk/include/iprt/process.h	(revision 80568)
+++ /trunk/include/iprt/process.h	(revision 80569)
@@ -168,4 +168,7 @@
  *                      NULL wif pszAsUser is NULL.  Whether this is actually
  *                      used or not depends on the platform.
+ * @param   pvExtraData Points to additional data as per @a fFlags:
+ *                          - RTPROC_FLAGS_DESIRED_SESSION_ID: Pointing to a
+ *                            uint32_t variable with the desired session ID.
  * @param   phProcess   Where to store the process handle on successful return.
  *                      The content is not changed on failure.  NULL is allowed.
@@ -180,5 +183,5 @@
 RTR3DECL(int)   RTProcCreateEx(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags,
                                PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser,
-                               const char *pszPassword, PRTPROCESS phProcess);
+                               const char *pszPassword, void *pvExtraData, PRTPROCESS phProcess);
 
 /** @name RTProcCreate and RTProcCreateEx flags
@@ -228,6 +231,10 @@
 /** Hint that we don't expect to ever want to wait on the process. */
 #define RTPROC_FLAGS_NO_WAIT                RT_BIT(10)
+/** For use with RTPROC_FLAGS_SERVICE to specify a desired session ID
+ * (Windows only, ignored elsewhere).  The @a pvExtraData argument points to
+ * a uint32_t containing the session ID, UINT32_MAX means any session. */
+#define RTPROC_FLAGS_DESIRED_SESSION_ID     RT_BIT(11)
 /** Valid flag mask. */
-#define RTPROC_FLAGS_VALID_MASK             UINT32_C(0x7ff)
+#define RTPROC_FLAGS_VALID_MASK             UINT32_C(0xfff)
 /** @}  */
 
Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp	(revision 80568)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlProcess.cpp	(revision 80569)
@@ -1298,5 +1298,5 @@
                 rc = RTProcCreateEx(szSysprepCmd, papszArgsExp, hEnv, 0 /* fFlags */,
                                     phStdIn, phStdOut, phStdErr, NULL /* pszAsUser */,
-                                    NULL /* pszPassword */, phProcess);
+                                    NULL /* pszPassword */, NULL, phProcess);
                 vgsvcGstCtrlProcessFreeArgv(papszArgsExp);
             }
@@ -1390,4 +1390,5 @@
                                 pszUser,
                                 pszPassword && *pszPassword ? pszPassword : NULL,
+                                NULL /*pvExtraData*/,
                                 phProcess);
 #ifdef RT_OS_WINDOWS
Index: /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp
===================================================================
--- /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp	(revision 80568)
+++ /trunk/src/VBox/Additions/common/VBoxService/VBoxServiceControlSession.cpp	(revision 80569)
@@ -2251,4 +2251,5 @@
                                     !fAnonymous ? pszUser : NULL,
                                     !fAnonymous ? pSessionThread->StartupInfo.szPassword : NULL,
+                                    NULL /*pvExtraData*/,
                                     &pSessionThread->hProcess);
             }
Index: /trunk/src/VBox/Frontends/Common/PasswordInput.cpp
===================================================================
--- /trunk/src/VBox/Frontends/Common/PasswordInput.cpp	(revision 80569)
+++ /trunk/src/VBox/Frontends/Common/PasswordInput.cpp	(revision 80569)
@@ -0,0 +1,151 @@
+/* $Id$ */
+/** @file
+ * Frontend shared bits - Password file and console input helpers.
+ */
+
+/*
+ * Copyright (C) 2012-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include "PasswordInput.h"
+
+#include <iprt/ctype.h>
+#include <iprt/message.h>
+#include <iprt/stream.h>
+
+#include <VBox/com/errorprint.h>
+
+
+/**
+ * Reads a password from the password file.
+ *
+ * Only first line is used. The passwords length must be less than 512 bytes
+ *
+ * @param   pszFilename  The path to file containing the password
+ * @param   pPasswd      The string where password will be returned
+ * @returns RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
+ */
+RTEXITCODE readPasswordFile(const char *pszFilename, com::Utf8Str *pPasswd)
+{
+    size_t cbFile;
+    char szPasswd[512] = { 0 };
+    int vrc = VINF_SUCCESS;
+    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+    bool fStdIn = !strcmp(pszFilename, "stdin");
+    PRTSTREAM pStrm;
+    if (!fStdIn)
+        vrc = RTStrmOpen(pszFilename, "r", &pStrm);
+    else
+        pStrm = g_pStdIn;
+    if (RT_SUCCESS(vrc))
+    {
+        vrc = RTStrmReadEx(pStrm, szPasswd, sizeof(szPasswd)-1, &cbFile);
+        if (RT_SUCCESS(vrc))
+        {
+            size_t cbSize = RT_MIN(sizeof(szPasswd)-1, cbFile);
+            unsigned i;
+            for (i = 0; i < cbSize && !RTLocCIsCntrl(szPasswd[i]); i++)
+                ;
+            szPasswd[i] = '\0';
+            /* If the line containing password doesn't fit into buffer */
+            if (i >= sizeof(szPasswd)-1 && cbFile >= sizeof(szPasswd))
+                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Provided password in file '%s' is too long", pszFilename);
+            else
+                *pPasswd = szPasswd;
+        }
+        else
+            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Cannot read password from file '%s': %Rrc", pszFilename, vrc);
+        if (!fStdIn)
+            RTStrmClose(pStrm);
+    }
+    else
+        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Cannot open password file '%s' (%Rrc)", pszFilename, vrc);
+
+    return rcExit;
+}
+
+
+/**
+ * Sets password for settings from password file
+ *
+ * Only first line is used. The passwords length must be less than 512 bytes
+ *
+ * @param virtualBox   The IVirtualBox interface the settings password will be set for
+ * @param pszFilename  The path to file containing the password
+ * @return RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
+ */
+RTEXITCODE settingsPasswordFile(ComPtr<IVirtualBox> virtualBox, const char *pszFilename)
+{
+    com::Utf8Str passwd;
+    RTEXITCODE rcExit = readPasswordFile(pszFilename, &passwd);
+    if (rcExit == RTEXITCODE_SUCCESS)
+    {
+        int rc;
+        CHECK_ERROR(virtualBox, SetSettingsSecret(com::Bstr(passwd).raw()));
+        if (FAILED(rc))
+            rcExit = RTEXITCODE_FAILURE;
+    }
+
+    return rcExit;
+}
+
+
+/**
+ * Gets the password from the user input
+ * *
+ * @param pPassword  The string where password will be returned
+ * @param pszPrompt  The prompt string for user
+ * @return RTEXITCODE_SUCCESS or RTEXITCODE_FAILURE + msg.
+ */
+RTEXITCODE readPasswordFromConsole(com::Utf8Str *pPassword, const char *pszPrompt, ...)
+{
+    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
+    char aszPwdInput[_1K] = { 0 };
+    va_list vaArgs;
+
+    va_start(vaArgs, pszPrompt);
+    int vrc = RTStrmPrintfV(g_pStdOut, pszPrompt, vaArgs);
+    if (RT_SUCCESS(vrc))
+    {
+        bool fEchoOld = false;
+        vrc = RTStrmInputGetEchoChars(g_pStdIn, &fEchoOld);
+        if (RT_SUCCESS(vrc))
+        {
+            vrc = RTStrmInputSetEchoChars(g_pStdIn, false);
+            if (RT_SUCCESS(vrc))
+            {
+                vrc = RTStrmGetLine(g_pStdIn, &aszPwdInput[0], sizeof(aszPwdInput));
+                if (RT_SUCCESS(vrc))
+                    *pPassword = aszPwdInput;
+                else
+                    rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed read password from command line (%Rrc)", vrc);
+
+                int vrc2 = RTStrmInputSetEchoChars(g_pStdIn, fEchoOld);
+                AssertRC(vrc2);
+            }
+            else
+                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to disable echoing typed characters (%Rrc)", vrc);
+        }
+        else
+            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to retrieve echo setting (%Rrc)", vrc);
+
+        RTStrmPutStr(g_pStdOut, "\n");
+    }
+    else
+        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to print prompt (%Rrc)", vrc);
+    va_end(vaArgs);
+
+    return rcExit;
+}
Index: /trunk/src/VBox/Frontends/Common/PasswordInput.h
===================================================================
--- /trunk/src/VBox/Frontends/Common/PasswordInput.h	(revision 80569)
+++ /trunk/src/VBox/Frontends/Common/PasswordInput.h	(revision 80569)
@@ -0,0 +1,34 @@
+/* $Id$ */
+/** @file
+ * Frontend shared bits - Password file and console input helpers.
+ */
+
+/*
+ * Copyright (C) 2012-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef VBOX_INCLUDED_SRC_Common_PasswordFileImpl_h
+#define VBOX_INCLUDED_SRC_Common_PasswordFileImpl_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <VBox/com/com.h>
+#include <VBox/com/ptr.h>
+#include <VBox/com/string.h>
+#include <VBox/com/VirtualBox.h>
+
+
+RTEXITCODE readPasswordFile(const char *pszFilename, com::Utf8Str *pPasswd);
+RTEXITCODE readPasswordFromConsole(com::Utf8Str *pPassword, const char *pszPrompt, ...);
+RTEXITCODE settingsPasswordFile(ComPtr<IVirtualBox> virtualBox, const char *pszFilename);
+
+#endif /* !VBOX_INCLUDED_SRC_VBoxAutostart_VBoxAutostart_h */
Index: /trunk/src/VBox/Frontends/VBoxAutostart/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Frontends/VBoxAutostart/Makefile.kmk	(revision 80568)
+++ /trunk/src/VBox/Frontends/VBoxAutostart/Makefile.kmk	(revision 80569)
@@ -22,4 +22,5 @@
  PROGRAMS += VBoxAutostartSvc
  VBoxAutostartSvc_TEMPLATE   = VBOXMAINCLIENTEXE
+ VBoxAutostartSvc_INCS       = ../Common
  VBoxAutostartSvc_SOURCES    = \
 	VBoxAutostartCfg.cpp \
@@ -27,5 +28,7 @@
 	VBoxAutostartStop.cpp \
 	VBoxAutostartUtils.cpp \
-	VBoxAutostart-win.cpp
+	VBoxAutostart-win.cpp \
+	../Common/PasswordInput.cpp
+ VBoxAutostartSvc_LIBS.win += Secur32.lib	
 else
  PROGRAMS += VBoxAutostart
Index: /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart-win.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart-win.cpp	(revision 80568)
+++ /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart-win.cpp	(revision 80569)
@@ -23,21 +23,27 @@
 #include <tchar.h>
 
+#define SECURITY_WIN32
+#include <Security.h>
+
+#include <VBox/com/array.h>
 #include <VBox/com/com.h>
-#include <VBox/com/string.h>
-#include <VBox/com/Guid.h>
-#include <VBox/com/array.h>
 #include <VBox/com/ErrorInfo.h>
 #include <VBox/com/errorprint.h>
-
+#include <VBox/com/Guid.h>
+#include <VBox/com/listeners.h>
 #include <VBox/com/NativeEventQueue.h>
-#include <VBox/com/listeners.h>
+#include <VBox/com/string.h>
 #include <VBox/com/VirtualBox.h>
 
 #include <VBox/log.h>
 #include <VBox/version.h>
+
+#include <iprt/env.h>
 #include <iprt/errcore.h>
+#include <iprt/getopt.h>
 #include <iprt/initterm.h>
 #include <iprt/mem.h>
-#include <iprt/getopt.h>
+#include <iprt/process.h>
+#include <iprt/path.h>
 #include <iprt/semaphore.h>
 #include <iprt/stream.h>
@@ -46,4 +52,5 @@
 
 #include "VBoxAutostart.h"
+#include "PasswordInput.h"
 
 
@@ -71,4 +78,6 @@
 /** The semaphore the main service thread is waiting on in autostartSvcWinServiceMain. */
 static RTSEMEVENTMULTI g_hSupSvcWinEvent = NIL_RTSEMEVENTMULTI;
+/** The service name is used for send to service main. */
+static com::Bstr g_bstrServiceName;
 
 
@@ -77,4 +86,95 @@
 *********************************************************************************************************************************/
 static SC_HANDLE autostartSvcWinOpenSCManager(const char *pszAction, DWORD dwAccess);
+
+static int autostartGetProcessDomainUser(com::Utf8Str &aUser)
+{
+    int rc = VERR_NOT_SUPPORTED;
+
+    RTUTF16 wszUsername[1024] = { 0 };
+    ULONG   cwcUsername = RT_ELEMENTS(wszUsername);
+    char *pszUser = NULL;
+    if (!GetUserNameExW(NameSamCompatible, &wszUsername[0], &cwcUsername))
+        return RTErrConvertFromWin32(GetLastError());
+    rc = RTUtf16ToUtf8(wszUsername, &pszUser);
+    aUser = pszUser;
+    RTStrFree(pszUser);
+    return rc;
+}
+
+static int autostartGetLocalDomain(com::Utf8Str &aDomain)
+{
+    RTUTF16 pwszDomain[MAX_COMPUTERNAME_LENGTH + 1] = { 0 };
+    uint32_t cwcDomainSize =  MAX_COMPUTERNAME_LENGTH + 1;
+    if (!GetComputerNameW(pwszDomain, (LPDWORD)&cwcDomainSize))
+        return RTErrConvertFromWin32(GetLastError());
+    char *pszDomain = NULL;
+    int rc = RTUtf16ToUtf8(pwszDomain, &pszDomain);
+    aDomain = pszDomain;
+    RTStrFree(pszDomain);
+    return rc;
+}
+
+static int autostartGetDomainAndUser(const com::Utf8Str &aDomainAndUser, com::Utf8Str &aDomain, com::Utf8Str &aUser)
+{
+    size_t offDelim = aDomainAndUser.find("\\");
+    if (offDelim != aDomainAndUser.npos)
+    {
+        // if only domain is specified
+        if (aDomainAndUser.length() - offDelim == 1)
+            return VERR_INVALID_PARAMETER;
+
+        if (offDelim == 1 && aDomainAndUser[0] == '.')
+        {
+            int rc = autostartGetLocalDomain(aDomain);
+            aUser = aDomainAndUser.substr(offDelim + 1);
+            return rc;
+        }
+        aDomain = aDomainAndUser.substr(0, offDelim);
+        aUser   = aDomainAndUser.substr(offDelim + 1);
+        return VINF_SUCCESS;
+    }
+
+    offDelim = aDomainAndUser.find("@");
+    if (offDelim != aDomainAndUser.npos)
+    {
+        // if only domain is specified
+        if (offDelim == 0)
+            return VERR_INVALID_PARAMETER;
+
+        // with '@' but without domain
+        if (aDomainAndUser.length() - offDelim == 1)
+        {
+            int rc = autostartGetLocalDomain(aDomain);
+            aUser = aDomainAndUser.substr(0, offDelim);
+            return rc;
+        }
+        aDomain = aDomainAndUser.substr(offDelim + 1);
+        aUser   = aDomainAndUser.substr(0, offDelim);
+        return VINF_SUCCESS;
+    }
+
+    // only user is specified
+    int rc = autostartGetLocalDomain(aDomain);
+    aUser = aDomainAndUser;
+    return rc;
+}
+
+/** Common helper for formatting the service name. */
+static void autostartFormatServiceName(const com::Utf8Str &aDomain, const com::Utf8Str &aUser, com::Utf8Str &aServiceName)
+{
+    aServiceName.printf("%s%s%s", AUTOSTART_SERVICE_NAME, aDomain.c_str(), aUser.c_str());
+}
+
+/** Used by the delete service operation. */
+static int autostartGetServiceName(const com::Utf8Str &aDomainAndUser, com::Utf8Str &aServiceName)
+{
+    com::Utf8Str sDomain;
+    com::Utf8Str sUser;
+    int rc = autostartGetDomainAndUser(aDomainAndUser, sDomain, sUser);
+    if (RT_FAILURE(rc))
+        return rc;
+    autostartFormatServiceName(sDomain, sUser, aServiceName);
+    return VINF_SUCCESS;
+}
 
 /**
@@ -228,5 +328,5 @@
  * @param   ...                 Errors codes that should not cause a message to be displayed.
  */
-static SC_HANDLE autostartSvcWinOpenService(const char *pszAction, DWORD dwSCMAccess, DWORD dwSVCAccess,
+static SC_HANDLE autostartSvcWinOpenService(const PRTUTF16 pwszServiceName, const char *pszAction, DWORD dwSCMAccess, DWORD dwSVCAccess,
                                             unsigned cIgnoredErrors, ...)
 {
@@ -235,5 +335,5 @@
         return NULL;
 
-    SC_HANDLE hSvc = OpenServiceA(hSCM, AUTOSTART_SERVICE_NAME, dwSVCAccess);
+    SC_HANDLE hSvc = OpenServiceW(hSCM, pwszServiceName, dwSVCAccess);
     if (hSvc)
     {
@@ -258,5 +358,6 @@
                     break;
                 case ERROR_SERVICE_DOES_NOT_EXIST:
-                    autostartSvcDisplayError("%s - OpenService failure: The service does not exist. Reinstall it.\n", pszAction);
+                    autostartSvcDisplayError("%s - OpenService failure: The service %ls does not exist. Reinstall it.\n",
+                                             pszAction, pwszServiceName);
                     break;
                 default:
@@ -356,10 +457,11 @@
      */
     bool fVerbose = false;
+    const char *pszUser = NULL;
     static const RTGETOPTDEF s_aOptions[] =
     {
-        { "--verbose", 'v', RTGETOPT_REQ_NOTHING }
+        { "--verbose", 'v', RTGETOPT_REQ_NOTHING },
+        { "--user",    'u', RTGETOPT_REQ_STRING  },
     };
     int ch;
-    unsigned iArg = 0;
     RTGETOPTUNION Value;
     RTGETOPTSTATE GetState;
@@ -372,18 +474,25 @@
                 fVerbose = true;
                 break;
-            case VINF_GETOPT_NOT_OPTION:
-                return autostartSvcDisplayTooManyArgsError("delete", argc, argv, iArg);
+            case 'u':
+                pszUser = Value.psz;
+                break;
             default:
-                return autostartSvcDisplayGetOptError("delete", ch, argc, argv, iArg, &Value);
-        }
-
-        iArg++;
-    }
-
+                return autostartSvcDisplayGetOptError("delete", ch, &Value);
+        }
+    }
+
+    if (!pszUser)
+        return autostartSvcDisplayError("delete - DeleteService failed, user name required.\n");
+
+    com::Utf8Str sServiceName;
+    int vrc = autostartGetServiceName(pszUser, sServiceName);
+    if (!RT_FAILURE(vrc))
+        return autostartSvcDisplayError("delete - DeleteService failed, service name for user %s can not be constructed.\n", 
+                                        pszUser);
     /*
      * Create the service.
      */
-    int rc = RTEXITCODE_FAILURE;
-    SC_HANDLE hSvc = autostartSvcWinOpenService("delete", SERVICE_CHANGE_CONFIG, DELETE,
+    RTEXITCODE rc = RTEXITCODE_FAILURE;
+    SC_HANDLE hSvc = autostartSvcWinOpenService(com::Bstr(sServiceName).raw(), "delete", SERVICE_CHANGE_CONFIG, DELETE,
                                                 1, ERROR_SERVICE_DOES_NOT_EXIST);
     if (hSvc)
@@ -391,5 +500,5 @@
         if (DeleteService(hSvc))
         {
-            RTPrintf("Successfully deleted the %s service.\n", AUTOSTART_SERVICE_NAME);
+            RTPrintf("Successfully deleted the %s service.\n", sServiceName.c_str());
             rc = RTEXITCODE_SUCCESS;
         }
@@ -402,7 +511,7 @@
 
         if (fVerbose)
-            RTPrintf("The service %s was not installed, nothing to be done.", AUTOSTART_SERVICE_NAME);
+            RTPrintf("The service %s was not installed, nothing to be done.", sServiceName.c_str());
         else
-            RTPrintf("Successfully deleted the %s service.\n", AUTOSTART_SERVICE_NAME);
+            RTPrintf("Successfully deleted the %s service.\n", sServiceName.c_str());
         rc = RTEXITCODE_SUCCESS;
     }
@@ -425,12 +534,12 @@
     bool fVerbose = false;
     const char *pszUser = NULL;
-    const char *pszPwd = NULL;
+    com::Utf8Str strPwd;
+    const char *pszPwdFile = NULL;
     static const RTGETOPTDEF s_aOptions[] =
     {
-        { "--verbose",  'v', RTGETOPT_REQ_NOTHING },
-        { "--user",     'u', RTGETOPT_REQ_STRING  },
-        { "--password", 'p', RTGETOPT_REQ_STRING  }
+        { "--verbose",       'v', RTGETOPT_REQ_NOTHING },
+        { "--user",          'u', RTGETOPT_REQ_STRING  },
+        { "--password-file", 'p', RTGETOPT_REQ_STRING  }
     };
-    int iArg = 0;
     int ch;
     RTGETOPTUNION Value;
@@ -448,13 +557,42 @@
                 break;
             case 'p':
-                pszPwd = Value.psz;
+                pszPwdFile = Value.psz;
                 break;
             default:
-                return autostartSvcDisplayGetOptError("create", ch, argc, argv, iArg, &Value);
-        }
-        iArg++;
-    }
-    if (iArg != argc)
-        return autostartSvcDisplayTooManyArgsError("create", argc, argv, iArg);
+                return autostartSvcDisplayGetOptError("create", ch, &Value);
+        }
+    }
+
+    if (!pszUser)
+        return autostartSvcDisplayError("Username is missing");
+
+    if (pszPwdFile)
+    {
+        /* Get password from file. */
+        RTEXITCODE rcExit = readPasswordFile(pszPwdFile, &strPwd);
+        if (rcExit == RTEXITCODE_FAILURE)
+            return rcExit;
+    }
+    else
+    {
+        /* Get password from console. */
+        RTEXITCODE rcExit = readPasswordFromConsole(&strPwd, "Enter password:");
+        if (rcExit == RTEXITCODE_FAILURE)
+            return rcExit;
+    }
+
+    if (strPwd.isEmpty())
+        return autostartSvcDisplayError("Password is missing");
+
+    com::Utf8Str sDomain;
+    com::Utf8Str sUserTmp;
+    int vrc = autostartGetDomainAndUser(pszUser, sDomain, sUserTmp);
+    if (RT_FAILURE(vrc))
+        return autostartSvcDisplayError("create - CreateService failed, failed to get domain and user from string %s (%d).\n",
+                                        pszUser, vrc);
+    com::Utf8StrFmt sUserFullName("%s\\%s", sDomain.c_str(), sUserTmp.c_str());
+    com::Utf8StrFmt sDisplayName("%s %s@%s", AUTOSTART_SERVICE_DISPLAY_NAME, sUserTmp.c_str(), sDomain.c_str());
+    com::Utf8Str    sServiceName;
+    autostartFormatServiceName(sDomain, sUserTmp, sServiceName);
 
     /*
@@ -465,27 +603,31 @@
     if (hSCM)
     {
-        char szExecPath[MAX_PATH];
-        if (GetModuleFileNameA(NULL /* the executable */, szExecPath, sizeof(szExecPath)))
+        char szExecPath[RTPATH_MAX];
+        if (RTProcGetExecutablePath(szExecPath, sizeof(szExecPath)))
         {
             if (fVerbose)
                 RTPrintf("Creating the %s service, binary \"%s\"...\n",
-                         AUTOSTART_SERVICE_NAME, szExecPath); /* yea, the binary name isn't UTF-8, but wtf. */
-
-            SC_HANDLE hSvc = CreateServiceA(hSCM,                            /* hSCManager */
-                                            AUTOSTART_SERVICE_NAME,          /* lpServiceName */
-                                            AUTOSTART_SERVICE_DISPLAY_NAME,  /* lpDisplayName */
+                         sServiceName.c_str(), szExecPath); /* yea, the binary name isn't UTF-8, but wtf. */
+
+            /*
+             * Add service name as command line parameter for the service
+             */
+            com::Utf8StrFmt sCmdLine("\"%s\" --service=%s", szExecPath, sServiceName.c_str());
+            SC_HANDLE hSvc = CreateServiceW(hSCM,                            /* hSCManager */
+                                            com::Bstr(sServiceName).raw(),   /* lpServiceName */
+                                            com::Bstr(sDisplayName).raw(),   /* lpDisplayName */
                                             SERVICE_CHANGE_CONFIG | SERVICE_QUERY_STATUS | SERVICE_QUERY_CONFIG, /* dwDesiredAccess */
                                             SERVICE_WIN32_OWN_PROCESS,       /* dwServiceType ( | SERVICE_INTERACTIVE_PROCESS? ) */
                                             SERVICE_AUTO_START,              /* dwStartType */
                                             SERVICE_ERROR_NORMAL,            /* dwErrorControl */
-                                            szExecPath,                      /* lpBinaryPathName */
+                                            com::Bstr(sCmdLine).raw(),       /* lpBinaryPathName */
                                             NULL,                            /* lpLoadOrderGroup */
                                             NULL,                            /* lpdwTagId */
                                             NULL,                            /* lpDependencies */
-                                            pszUser,                         /* lpServiceStartName (NULL => LocalSystem) */
-                                            pszPwd);                         /* lpPassword */
+                                            com::Bstr(sUserFullName).raw(),  /* lpServiceStartName (NULL => LocalSystem) */
+                                            com::Bstr(strPwd).raw());        /* lpPassword */
             if (hSvc)
             {
-                RTPrintf("Successfully created the %s service.\n", AUTOSTART_SERVICE_NAME);
+                RTPrintf("Successfully created the %s service.\n", sServiceName.c_str());
                 /** @todo Set the service description or it'll look weird in the vista service manager.
                  *  Anything else that should be configured? Start access or something? */
@@ -631,13 +773,94 @@
 }
 
-static DECLCALLBACK(int) autostartWorkerThread(RTTHREAD hThreadSelf, void *pvUser)
-{
-    RT_NOREF(hThreadSelf, pvUser);
+static int autostartStartVMs()
+{
     int rc = autostartSetup();
 
-    /** @todo Implement config options. */
-    rc = autostartStartMain(NULL);
+    const char *pszConfigFile = RTEnvGet("VBOXAUTOSTART_CONFIG");
+    if (!pszConfigFile)
+        return autostartSvcLogError("Starting VMs failed. VBOXAUTOSTART_CONFIG environment variable is not defined.\n");
+    bool fAllow = false;
+
+    PCFGAST pCfgAst = NULL;
+    rc = autostartParseConfig(pszConfigFile, &pCfgAst);
     if (RT_FAILURE(rc))
-        autostartSvcLogError("Starting VMs failed, rc=%Rrc", rc);
+        return autostartSvcLogError("Starting VMs failed. Failed to parse the config file. Check the access permissions and file structure.\n");
+
+    PCFGAST pCfgAstPolicy = autostartConfigAstGetByName(pCfgAst, "default_policy");
+    /* Check default policy. */
+    if (pCfgAstPolicy)
+    {
+        if (   pCfgAstPolicy->enmType == CFGASTNODETYPE_KEYVALUE
+            && (   !RTStrCmp(pCfgAstPolicy->u.KeyValue.aszValue, "allow")
+                || !RTStrCmp(pCfgAstPolicy->u.KeyValue.aszValue, "deny")))
+        {
+            if (!RTStrCmp(pCfgAstPolicy->u.KeyValue.aszValue, "allow"))
+                fAllow = true;
+        }
+        else
+        {
+            autostartConfigAstDestroy(pCfgAst);
+            return autostartSvcLogError("'default_policy' must be either 'allow' or 'deny'.\n");
+        }
+    }
+
+    com::Utf8Str sUser;
+    rc = autostartGetProcessDomainUser(sUser);
+    if (RT_FAILURE(rc))
+    {
+        autostartConfigAstDestroy(pCfgAst);
+        return autostartSvcLogError("Failed to query username of the process (%Rrc).\n", rc);
+    }
+
+    PCFGAST pCfgAstUser = NULL;
+    for (unsigned i = 0; i < pCfgAst->u.Compound.cAstNodes; i++)
+    {
+        PCFGAST pNode = pCfgAst->u.Compound.apAstNodes[i];
+        com::Utf8Str sDomain;
+        com::Utf8Str sUserTmp;
+        int rc = autostartGetDomainAndUser(pNode->pszKey, sDomain, sUserTmp);
+        if (RT_FAILURE(rc))
+            continue;
+        com::Utf8StrFmt sDomainUser("%s\\%s", sDomain.c_str(), sUserTmp.c_str());
+        if (sDomainUser == sUser)
+        {
+            pCfgAstUser = pNode;
+            break;
+        }
+    }
+
+    if (   pCfgAstUser
+        && pCfgAstUser->enmType == CFGASTNODETYPE_COMPOUND)
+    {
+        pCfgAstPolicy = autostartConfigAstGetByName(pCfgAstUser, "allow");
+        if (pCfgAstPolicy)
+        {
+            if (   pCfgAstPolicy->enmType == CFGASTNODETYPE_KEYVALUE
+                && (   !RTStrCmp(pCfgAstPolicy->u.KeyValue.aszValue, "true")
+                    || !RTStrCmp(pCfgAstPolicy->u.KeyValue.aszValue, "false")))
+                fAllow = RTStrCmp(pCfgAstPolicy->u.KeyValue.aszValue, "true") == 0;
+            else
+            {
+                autostartConfigAstDestroy(pCfgAst);
+                return autostartSvcLogError("'allow' must be either 'true' or 'false'.\n");
+            }
+        }
+    }
+    else if (pCfgAstUser)
+    {
+        autostartConfigAstDestroy(pCfgAst);
+        return autostartSvcLogError("Invalid config, user is not a compound node.\n");
+    }
+
+    if (!fAllow)
+    {
+        autostartConfigAstDestroy(pCfgAst);
+        return autostartSvcLogError("User is not allowed to autostart VMs.\n");
+    }
+
+    rc = autostartStartMain(pCfgAstUser);
+    autostartConfigAstDestroy(pCfgAst);
+    if (RT_FAILURE(rc))
+        autostartSvcLogError("Starting VMs failed, rc=%Rrc\n", rc);
 
     return rc;
@@ -651,9 +874,9 @@
  *
  * @param   cArgs           Argument count.
- * @param   papszArgs       Argument vector.
- */
-static VOID WINAPI autostartSvcWinServiceMain(DWORD cArgs, LPTSTR *papszArgs)
-{
-    RT_NOREF(papszArgs);
+ * @param   papwszArgs      Argument vector.
+ */
+static VOID WINAPI autostartSvcWinServiceMain(DWORD cArgs, LPWSTR *papwszArgs)
+{
+    RT_NOREF(papwszArgs);
     LogFlowFuncEnter();
 
@@ -662,5 +885,5 @@
      */
     Assert(g_u32SupSvcWinStatus == SERVICE_STOPPED);
-    g_hSupSvcWinCtrlHandler = RegisterServiceCtrlHandlerExA(AUTOSTART_SERVICE_NAME, autostartSvcWinServiceCtrlHandlerEx, NULL);
+    g_hSupSvcWinCtrlHandler = RegisterServiceCtrlHandlerExW(g_bstrServiceName.raw(), autostartSvcWinServiceCtrlHandlerEx, NULL);
     if (g_hSupSvcWinCtrlHandler)
     {
@@ -682,19 +905,20 @@
                     if (autostartSvcWinSetServiceStatus(SERVICE_RUNNING, 0, 0))
                     {
-                        LogFlow(("autostartSvcWinServiceMain: calling RTSemEventMultiWait\n"));
-                        RTTHREAD hWorker;
-                        RTThreadCreate(&hWorker, autostartWorkerThread, NULL, 0, RTTHREADTYPE_DEFAULT, 0, "WorkerThread");
-
-                        LogFlow(("autostartSvcWinServiceMain: woke up\n"));
-                        err = NO_ERROR;
-                        rc = RTSemEventMultiWait(g_hSupSvcWinEvent, RT_INDEFINITE_WAIT);
+                        LogFlow(("autostartSvcWinServiceMain: calling autostartStartVMs\n"));
+                        rc = autostartStartVMs();
                         if (RT_SUCCESS(rc))
                         {
-                            LogFlow(("autostartSvcWinServiceMain: woke up\n"));
-                            /** @todo Autostop part. */
+                            LogFlow(("autostartSvcWinServiceMain: done string VMs\n"));
                             err = NO_ERROR;
+                            rc = RTSemEventMultiWait(g_hSupSvcWinEvent, RT_INDEFINITE_WAIT);
+                            if (RT_SUCCESS(rc))
+                            {
+                                LogFlow(("autostartSvcWinServiceMain: woke up\n"));
+                                /** @todo Autostop part. */
+                                err = NO_ERROR;
+                            }
+                            else
+                                autostartSvcLogError("RTSemEventWait failed, rc=%Rrc", rc);
                         }
-                        else
-                            autostartSvcLogError("RTSemEventWait failed, rc=%Rrc", rc);
 
                         autostartShutdown();
@@ -703,5 +927,5 @@
                     {
                         err = GetLastError();
-                        autostartSvcLogError("SetServiceStatus failed, err=%d", err);
+                        autostartSvcLogError("SetServiceStatus failed, err=%u", err);
                     }
 
@@ -718,10 +942,10 @@
         {
             err = GetLastError();
-            autostartSvcLogError("SetServiceStatus failed, err=%d", err);
+            autostartSvcLogError("SetServiceStatus failed, err=%u", err);
         }
         autostartSvcWinSetServiceStatus(SERVICE_STOPPED, 0, err);
     }
     else
-        autostartSvcLogError("RegisterServiceCtrlHandlerEx failed, err=%d", GetLastError());
+        autostartSvcLogError("RegisterServiceCtrlHandlerEx failed, err=%u", GetLastError());
 
     LogFlowFuncLeave();
@@ -750,7 +974,83 @@
     static const RTGETOPTDEF s_aOptions[] =
     {
-        { "--dummy", 'd', RTGETOPT_REQ_NOTHING }
+        { "--service", 's', RTGETOPT_REQ_STRING },
     };
-    int iArg = 0;
+
+    const char *pszServiceName = NULL;
+    int ch;
+    RTGETOPTUNION Value;
+    RTGETOPTSTATE GetState;
+    RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
+    while ((ch = RTGetOpt(&GetState, &Value)))
+    {
+        switch (ch)
+        {
+            case 's':
+                pszServiceName = Value.psz;
+                try
+                {
+                    g_bstrServiceName = com::Bstr(Value.psz);
+                }
+                catch (...)
+                {
+                    autostartSvcLogError("runit failed, service name is not valid utf-8 string or out of memory");
+                    return RTEXITCODE_FAILURE;
+                }
+                break;
+            default:
+                return autostartSvcDisplayGetOptError("runit", ch, &Value);
+        }
+    }
+
+    if (!pszServiceName)
+    {
+        autostartSvcLogError("runit failed, service name is missing");
+        return RTEXITCODE_FAILURE;
+    }
+
+    /*
+     * Register the service with the service control manager
+     * and start dispatching requests from it (all done by the API).
+     */
+    SERVICE_TABLE_ENTRYW const s_aServiceStartTable[] =
+    {
+        { g_bstrServiceName.raw(), autostartSvcWinServiceMain },
+        { NULL, NULL}
+    };
+    if (StartServiceCtrlDispatcherW(&s_aServiceStartTable[0]))
+    {
+        LogFlowFuncLeave();
+        return RTEXITCODE_SUCCESS; /* told to quit, so quit. */
+    }
+
+    DWORD err = GetLastError();
+    switch (err)
+    {
+        case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
+            autostartSvcWinServiceMain(0, NULL);//autostartSvcDisplayError("Cannot run a service from the command line. Use the 'start' action to start it the right way.\n");
+            break;
+        default:
+            autostartSvcLogError("StartServiceCtrlDispatcher failed, err=%u", err);
+            break;
+    }
+    return RTEXITCODE_FAILURE;
+}
+
+
+/**
+ * Show the version info.
+ *
+ * @returns RTEXITCODE_SUCCESS.
+ */
+static RTEXITCODE autostartSvcWinShowVersion(int argc, char **argv)
+{
+    /*
+     * Parse the arguments.
+     */
+    bool fBrief = false;
+    static const RTGETOPTDEF s_aOptions[] =
+    {
+        { "--brief", 'b', RTGETOPT_REQ_NOTHING }
+    };
     int ch;
     RTGETOPTUNION Value;
@@ -760,67 +1060,7 @@
         switch (ch)
         {
-            default:    return autostartSvcDisplayGetOptError("runit", ch, argc, argv, iArg, &Value);
-        }
-    if (iArg != argc)
-        return autostartSvcDisplayTooManyArgsError("runit", argc, argv, iArg);
-
-    /*
-     * Register the service with the service control manager
-     * and start dispatching requests from it (all done by the API).
-     */
-    static SERVICE_TABLE_ENTRY const s_aServiceStartTable[] =
-    {
-        { _T(AUTOSTART_SERVICE_NAME), autostartSvcWinServiceMain },
-        { NULL, NULL}
-    };
-    if (StartServiceCtrlDispatcher(&s_aServiceStartTable[0]))
-    {
-        LogFlowFuncLeave();
-        return RTEXITCODE_SUCCESS; /* told to quit, so quit. */
-    }
-
-    DWORD err = GetLastError();
-    switch (err)
-    {
-        case ERROR_FAILED_SERVICE_CONTROLLER_CONNECT:
-            autostartSvcWinServiceMain(0, NULL);//autostartSvcDisplayError("Cannot run a service from the command line. Use the 'start' action to start it the right way.\n");
-            break;
-        default:
-            autostartSvcLogError("StartServiceCtrlDispatcher failed, err=%d", err);
-            break;
-    }
-    return RTEXITCODE_FAILURE;
-}
-
-
-/**
- * Show the version info.
- *
- * @returns RTEXITCODE_SUCCESS.
- */
-static RTEXITCODE autostartSvcWinShowVersion(int argc, char **argv)
-{
-    /*
-     * Parse the arguments.
-     */
-    bool fBrief = false;
-    static const RTGETOPTDEF s_aOptions[] =
-    {
-        { "--brief", 'b', RTGETOPT_REQ_NOTHING }
-    };
-    int iArg = 0;
-    int ch;
-    RTGETOPTUNION Value;
-    RTGETOPTSTATE GetState;
-    RTGetOptInit(&GetState, argc, argv, s_aOptions, RT_ELEMENTS(s_aOptions), 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
-    while ((ch = RTGetOpt(&GetState, &Value)))
-        switch (ch)
-        {
             case 'b':   fBrief = true;  break;
-            default:    return autostartSvcDisplayGetOptError("version", ch, argc, argv, iArg, &Value);
-
-        }
-    if (iArg != argc)
-        return autostartSvcDisplayTooManyArgsError("version", argc, argv, iArg);
+            default:    return autostartSvcDisplayGetOptError("version", ch, &Value);
+        }
 
     /*
Index: /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart.h
===================================================================
--- /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart.h	(revision 80568)
+++ /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostart.h	(revision 80569)
@@ -253,5 +253,5 @@
  * @todo    This should later be replaced by the release logger and callback destination(s).
  */
-DECLHIDDEN(void) autostartSvcLogErrorV(const char *pszFormat, va_list va);
+DECLHIDDEN(RTEXITCODE) autostartSvcLogErrorV(const char *pszFormat, va_list va);
 
 /**
@@ -265,5 +265,5 @@
  * @todo    This should later be replaced by the release logger and callback destination(s).
  */
-DECLHIDDEN(void) autostartSvcLogError(const char *pszFormat, ...);
+DECLHIDDEN(RTEXITCODE) autostartSvcLogError(const char *pszFormat, ...);
 
 /**
@@ -297,5 +297,5 @@
  * @param   va          Format arguments.
  */
-DECLHIDDEN(void) autostartSvcDisplayErrorV(const char *pszFormat, va_list va);
+DECLHIDDEN(RTEXITCODE) autostartSvcDisplayErrorV(const char *pszFormat, va_list va);
 
 /**
@@ -305,29 +305,15 @@
  * @param   ...         Format arguments.
  */
-DECLHIDDEN(void) autostartSvcDisplayError(const char *pszFormat, ...);
-
-/**
- * Deals with RTGetOpt failure.
- *
- * @returns 1
+DECLHIDDEN(RTEXITCODE) autostartSvcDisplayError(const char *pszFormat, ...);
+
+/**
+ * Deals with RTGetOpt failure, i.e. an syntax error.
+ *
+ * @returns RTEXITCODE_SYNTAX
  * @param   pszAction       The action name.
  * @param   rc              The RTGetOpt return value.
- * @param   argc            The argument count.
- * @param   argv            The argument vector.
- * @param   iArg            The argument index.
  * @param   pValue          The value returned by RTGetOpt.
  */
-DECLHIDDEN(RTEXITCODE) autostartSvcDisplayGetOptError(const char *pszAction, int rc, int argc, char **argv, int iArg, PCRTGETOPTUNION pValue);
-
-/**
- * Bitch about too many arguments (after RTGetOpt stops).
- *
- * @returns RTEXITCODE_FAILURE
- * @param   pszAction       The action name.
- * @param   argc            The argument count.
- * @param   argv            The argument vector.
- * @param   iArg            The argument index.
- */
-DECLHIDDEN(RTEXITCODE) autostartSvcDisplayTooManyArgsError(const char *pszAction, int argc, char **argv, int iArg);
+DECLHIDDEN(RTEXITCODE) autostartSvcDisplayGetOptError(const char *pszAction, int rc, PCRTGETOPTUNION pValue);
 
 DECLHIDDEN(int) autostartSetup();
Index: /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartUtils.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartUtils.cpp	(revision 80568)
+++ /trunk/src/VBox/Frontends/VBoxAutostart/VBoxAutostartUtils.cpp	(revision 80569)
@@ -94,5 +94,5 @@
 }
 
-DECLHIDDEN(void) autostartSvcLogErrorV(const char *pszFormat, va_list va)
+DECLHIDDEN(RTEXITCODE) autostartSvcLogErrorV(const char *pszFormat, va_list va)
 {
     if (*pszFormat)
@@ -107,7 +107,8 @@
             autostartSvcOsLogStr(pszFormat, AUTOSTARTLOGTYPE_ERROR);
     }
-}
-
-DECLHIDDEN(void) autostartSvcLogError(const char *pszFormat, ...)
+    return RTEXITCODE_FAILURE;
+}
+
+DECLHIDDEN(RTEXITCODE) autostartSvcLogError(const char *pszFormat, ...)
 {
     va_list va;
@@ -115,4 +116,5 @@
     autostartSvcLogErrorV(pszFormat, va);
     va_end(va);
+    return RTEXITCODE_FAILURE;
 }
 
@@ -203,12 +205,13 @@
 }
 
-DECLHIDDEN(void) autostartSvcDisplayErrorV(const char *pszFormat, va_list va)
+DECLHIDDEN(RTEXITCODE) autostartSvcDisplayErrorV(const char *pszFormat, va_list va)
 {
     RTStrmPrintf(g_pStdErr, "VBoxSupSvc error: ");
     RTStrmPrintfV(g_pStdErr, pszFormat, va);
     Log(("autostartSvcDisplayErrorV: %s", pszFormat)); /** @todo format it! */
-}
-
-DECLHIDDEN(void) autostartSvcDisplayError(const char *pszFormat, ...)
+    return RTEXITCODE_FAILURE;
+}
+
+DECLHIDDEN(RTEXITCODE) autostartSvcDisplayError(const char *pszFormat, ...)
 {
     va_list va;
@@ -216,21 +219,13 @@
     autostartSvcDisplayErrorV(pszFormat, va);
     va_end(va);
-}
-
-DECLHIDDEN(RTEXITCODE) autostartSvcDisplayGetOptError(const char *pszAction, int rc, int argc, char **argv, int iArg,
-                                                      PCRTGETOPTUNION pValue)
-{
-    RT_NOREF(pValue);
-    autostartSvcDisplayError("%s - RTGetOpt failure, %Rrc (%d): %s\n",
-                       pszAction, rc, rc, iArg < argc ? argv[iArg] : "<null>");
-    return RTEXITCODE_FAILURE;
-}
-
-DECLHIDDEN(RTEXITCODE) autostartSvcDisplayTooManyArgsError(const char *pszAction, int argc, char **argv, int iArg)
-{
-    RT_NOREF(argc);
-    Assert(iArg < argc);
-    autostartSvcDisplayError("%s - Too many arguments: %s\n", pszAction, argv[iArg]);
-    return RTEXITCODE_FAILURE;
+    return RTEXITCODE_FAILURE;
+}
+
+DECLHIDDEN(RTEXITCODE) autostartSvcDisplayGetOptError(const char *pszAction, int rc, PCRTGETOPTUNION pValue)
+{
+    char szMsg[4096];
+    RTGetOptFormatError(szMsg, sizeof(szMsg), rc, pValue);
+    autostartSvcDisplayError("%s - %s", pszAction, szMsg);
+    return RTEXITCODE_SYNTAX;
 }
 
Index: /trunk/src/VBox/Frontends/VBoxBugReport/VBoxBugReport.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxBugReport/VBoxBugReport.cpp	(revision 80568)
+++ /trunk/src/VBox/Frontends/VBoxBugReport/VBoxBugReport.cpp	(revision 80569)
@@ -367,5 +367,5 @@
     handleRtError(RTProcCreateEx(m_papszArgs[0], m_papszArgs, RTENV_DEFAULT, 0,
                                  NULL, &hStdOutErr, &hStdOutErr,
-                                 NULL, NULL, &hProcess),
+                                 NULL, NULL, NULL, &hProcess),
                   "Failed to create process '%s'", m_papszArgs[0]);
     RTPROCSTATUS status;
@@ -444,5 +444,5 @@
     handleRtError(RTProcCreateEx(m_papszArgs[0], m_papszArgs, RTENV_DEFAULT, 0,
                                  NULL, &hStdOutErr, &hStdOutErr,
-                                 NULL, NULL, &hProcess),
+                                 NULL, NULL, NULL, &hProcess),
                   "Failed to create process '%s'", m_papszArgs[0]);
     RTPROCSTATUS status;
Index: /trunk/src/VBox/Frontends/VBoxHeadless/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Frontends/VBoxHeadless/Makefile.kmk	(revision 80568)
+++ /trunk/src/VBox/Frontends/VBoxHeadless/Makefile.kmk	(revision 80569)
@@ -46,6 +46,10 @@
 VBoxHeadless_TEMPLATE  := $(if $(VBOX_WITH_HARDENING),VBOXMAINCLIENTDLL,VBOXMAINCLIENTEXE)
 VBoxHeadless_DEFS      += $(if $(VBOX_WITH_RECORDING),VBOX_WITH_RECORDING,)
-VBoxHeadless_INCS      = $(VBOX_GRAPHICS_INCS)
-VBoxHeadless_SOURCES    = VBoxHeadless.cpp
+VBoxHeadless_INCS      = \
+	$(VBOX_GRAPHICS_INCS) \
+	../Common
+VBoxHeadless_SOURCES    = \
+	VBoxHeadless.cpp \
+	../Common/PasswordInput.cpp
 ifdef VBOX_WITH_GUEST_PROPS
  VBoxHeadless_DEFS     += VBOX_WITH_GUEST_PROPS
Index: /trunk/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp	(revision 80568)
+++ /trunk/src/VBox/Frontends/VBoxHeadless/VBoxHeadless.cpp	(revision 80569)
@@ -60,4 +60,6 @@
 #include <signal.h>
 #endif
+
+#include "PasswordInput.h"
 
 ////////////////////////////////////////////////////////////////////////////////
@@ -525,68 +527,4 @@
 }
 #endif /* VBOX_WITH_RECORDING defined */
-
-static RTEXITCODE readPasswordFile(const char *pszFilename, com::Utf8Str *pPasswd)
-{
-    size_t cbFile;
-    char szPasswd[512];
-    int vrc = VINF_SUCCESS;
-    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
-    bool fStdIn = !strcmp(pszFilename, "stdin");
-    PRTSTREAM pStrm;
-    if (!fStdIn)
-        vrc = RTStrmOpen(pszFilename, "r", &pStrm);
-    else
-        pStrm = g_pStdIn;
-    if (RT_SUCCESS(vrc))
-    {
-        vrc = RTStrmReadEx(pStrm, szPasswd, sizeof(szPasswd)-1, &cbFile);
-        if (RT_SUCCESS(vrc))
-        {
-            if (cbFile >= sizeof(szPasswd)-1)
-            {
-                RTPrintf("Provided password in file '%s' is too long\n", pszFilename);
-                rcExit = RTEXITCODE_FAILURE;
-            }
-            else
-            {
-                unsigned i;
-                for (i = 0; i < cbFile && !RT_C_IS_CNTRL(szPasswd[i]); i++)
-                    ;
-                szPasswd[i] = '\0';
-                *pPasswd = szPasswd;
-            }
-        }
-        else
-        {
-            RTPrintf("Cannot read password from file '%s': %Rrc\n", pszFilename, vrc);
-            rcExit = RTEXITCODE_FAILURE;
-        }
-        if (!fStdIn)
-            RTStrmClose(pStrm);
-    }
-    else
-    {
-        RTPrintf("Cannot open password file '%s' (%Rrc)\n", pszFilename, vrc);
-        rcExit = RTEXITCODE_FAILURE;
-    }
-
-    return rcExit;
-}
-
-static RTEXITCODE settingsPasswordFile(ComPtr<IVirtualBox> virtualBox, const char *pszFilename)
-{
-    com::Utf8Str passwd;
-    RTEXITCODE rcExit = readPasswordFile(pszFilename, &passwd);
-    if (rcExit == RTEXITCODE_SUCCESS)
-    {
-        int rc;
-        CHECK_ERROR(virtualBox, SetSettingsSecret(com::Bstr(passwd).raw()));
-        if (FAILED(rc))
-            rcExit = RTEXITCODE_FAILURE;
-    }
-
-    return rcExit;
-}
-
 
 #ifdef RT_OS_DARWIN
Index: /trunk/src/VBox/Frontends/VBoxManage/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/Makefile.kmk	(revision 80568)
+++ /trunk/src/VBox/Frontends/VBoxManage/Makefile.kmk	(revision 80569)
@@ -66,5 +66,6 @@
  VBoxManage_DEFS.win   = _WIN32_WINNT=0x0500
  VBoxManage_INCS = \
- 	$(VBoxManage_0_OUTDIR)
+ 	$(VBoxManage_0_OUTDIR) \
+ 	../Common
  VBoxManage_INTERMEDIATES = \
  	$(VBoxManage_0_OUTDIR)/VBoxManageBuiltInHelp.h
@@ -94,5 +95,6 @@
  	$(if $(VBOX_WITH_NAT_SERVICE),VBoxManageNATNetwork.cpp,) \
  	$(if $(VBOX_WITH_NAT_SERVICE),../../NetworkServices/NetLib/VBoxNetPortForwardString.cpp,) \
- 	VBoxManageCloud.cpp
+ 	VBoxManageCloud.cpp \
+ 	../Common/PasswordInput.cpp
  VBoxManage_SOURCES.win = \
  	VBoxManage.rc
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManage.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManage.cpp	(revision 80568)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManage.cpp	(revision 80569)
@@ -365,96 +365,4 @@
 }
 
-RTEXITCODE readPasswordFile(const char *pszFilename, com::Utf8Str *pPasswd)
-{
-    size_t cbFile;
-    char szPasswd[512];
-    int vrc = VINF_SUCCESS;
-    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
-    bool fStdIn = !strcmp(pszFilename, "stdin");
-    PRTSTREAM pStrm;
-    if (!fStdIn)
-        vrc = RTStrmOpen(pszFilename, "r", &pStrm);
-    else
-        pStrm = g_pStdIn;
-    if (RT_SUCCESS(vrc))
-    {
-        vrc = RTStrmReadEx(pStrm, szPasswd, sizeof(szPasswd)-1, &cbFile);
-        if (RT_SUCCESS(vrc))
-        {
-            if (cbFile >= sizeof(szPasswd)-1)
-                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Provided password in file '%s' is too long", pszFilename);
-            else
-            {
-                unsigned i;
-                for (i = 0; i < cbFile && !RT_C_IS_CNTRL(szPasswd[i]); i++)
-                    ;
-                szPasswd[i] = '\0';
-                *pPasswd = szPasswd;
-            }
-        }
-        else
-            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Cannot read password from file '%s': %Rrc", pszFilename, vrc);
-        if (!fStdIn)
-            RTStrmClose(pStrm);
-    }
-    else
-        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Cannot open password file '%s' (%Rrc)", pszFilename, vrc);
-
-    return rcExit;
-}
-
-static RTEXITCODE settingsPasswordFile(ComPtr<IVirtualBox> virtualBox, const char *pszFilename)
-{
-    com::Utf8Str passwd;
-    RTEXITCODE rcExit = readPasswordFile(pszFilename, &passwd);
-    if (rcExit == RTEXITCODE_SUCCESS)
-    {
-        CHECK_ERROR2I_STMT(virtualBox, SetSettingsSecret(com::Bstr(passwd).raw()), rcExit = RTEXITCODE_FAILURE);
-    }
-
-    return rcExit;
-}
-
-RTEXITCODE readPasswordFromConsole(com::Utf8Str *pPassword, const char *pszPrompt, ...)
-{
-    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
-    char aszPwdInput[_1K] = { 0 };
-    va_list vaArgs;
-
-    va_start(vaArgs, pszPrompt);
-    int vrc = RTStrmPrintfV(g_pStdOut, pszPrompt, vaArgs);
-    if (RT_SUCCESS(vrc))
-    {
-        bool fEchoOld = false;
-        vrc = RTStrmInputGetEchoChars(g_pStdIn, &fEchoOld);
-        if (RT_SUCCESS(vrc))
-        {
-            vrc = RTStrmInputSetEchoChars(g_pStdIn, false);
-            if (RT_SUCCESS(vrc))
-            {
-                vrc = RTStrmGetLine(g_pStdIn, &aszPwdInput[0], sizeof(aszPwdInput));
-                if (RT_SUCCESS(vrc))
-                    *pPassword = aszPwdInput;
-                else
-                    rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed read password from command line (%Rrc)", vrc);
-
-                int vrc2 = RTStrmInputSetEchoChars(g_pStdIn, fEchoOld);
-                AssertRC(vrc2);
-            }
-            else
-                rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to disable echoing typed characters (%Rrc)", vrc);
-        }
-        else
-            rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to retrieve echo setting (%Rrc)", vrc);
-
-        RTStrmPutStr(g_pStdOut, "\n");
-    }
-    else
-        rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed to print prompt (%Rrc)", vrc);
-    va_end(vaArgs);
-
-    return rcExit;
-}
-
 #endif /* !VBOX_ONLY_DOCS */
 
Index: /trunk/src/VBox/Frontends/VBoxManage/VBoxManage.h
===================================================================
--- /trunk/src/VBox/Frontends/VBoxManage/VBoxManage.h	(revision 80568)
+++ /trunk/src/VBox/Frontends/VBoxManage/VBoxManage.h	(revision 80569)
@@ -37,4 +37,5 @@
 #ifndef VBOX_ONLY_DOCS
 # include "VBoxManageBuiltInHelp.h"
+# include "PasswordInput.h"
 #endif
 
@@ -218,7 +219,4 @@
 
 #ifndef VBOX_ONLY_DOCS
-RTEXITCODE readPasswordFile(const char *pszFilename, com::Utf8Str *pPasswd);
-RTEXITCODE readPasswordFromConsole(com::Utf8Str *pPassword, const char *pszPrompt, ...);
-
 RTEXITCODE handleInternalCommands(HandlerArg *a);
 #endif /* !VBOX_ONLY_DOCS */
Index: /trunk/src/VBox/Frontends/VBoxSDL/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Frontends/VBoxSDL/Makefile.kmk	(revision 80568)
+++ /trunk/src/VBox/Frontends/VBoxSDL/Makefile.kmk	(revision 80569)
@@ -46,5 +46,6 @@
 	VBoxSDL.cpp \
 	Framebuffer.cpp \
-	Helper.cpp
+	Helper.cpp \
+	../Common/PasswordInput.cpp
 VBoxSDL_SOURCES.darwin = \
 	VBoxSDLMain-darwin.m \
@@ -70,5 +71,6 @@
 VBoxSDL_INCS = \
 	$(VBoxSDL_0_OUTDIR) \
-	$(VBOX_GRAPHICS_INCS)
+	$(VBOX_GRAPHICS_INCS) \
+	../Common
 ifeq ($(filter-out freebsd linux netbsd openbsd solaris,$(KBUILD_TARGET)),) # X11
 VBoxSDL_INCS += \
Index: /trunk/src/VBox/Frontends/VBoxSDL/VBoxSDL.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VBoxSDL/VBoxSDL.cpp	(revision 80568)
+++ /trunk/src/VBox/Frontends/VBoxSDL/VBoxSDL.cpp	(revision 80569)
@@ -89,4 +89,6 @@
 #include <vector>
 #include <list>
+
+#include "PasswordInput.h"
 
 /* Xlib would re-define our enums */
@@ -170,6 +172,4 @@
 static int     WaitSDLEvent(SDL_Event *event);
 static void    SetFullscreen(bool enable);
-static RTEXITCODE readPasswordFile(const char *pszFilename, com::Utf8Str *pPasswd);
-static RTEXITCODE settingsPasswordFile(ComPtr<IVirtualBox> virtualBox, const char *pszFilename);
 
 #ifdef VBOX_WITH_SDL13
@@ -3120,67 +3120,4 @@
     RTLogFlush(NULL);
     return FAILED(rc) ? 1 : 0;
-}
-
-static RTEXITCODE readPasswordFile(const char *pszFilename, com::Utf8Str *pPasswd)
-{
-    size_t cbFile;
-    char szPasswd[512];
-    int vrc = VINF_SUCCESS;
-    RTEXITCODE rcExit = RTEXITCODE_SUCCESS;
-    bool fStdIn = !strcmp(pszFilename, "stdin");
-    PRTSTREAM pStrm;
-    if (!fStdIn)
-        vrc = RTStrmOpen(pszFilename, "r", &pStrm);
-    else
-        pStrm = g_pStdIn;
-    if (RT_SUCCESS(vrc))
-    {
-        vrc = RTStrmReadEx(pStrm, szPasswd, sizeof(szPasswd)-1, &cbFile);
-        if (RT_SUCCESS(vrc))
-        {
-            if (cbFile >= sizeof(szPasswd)-1)
-            {
-                RTPrintf("Provided password in file '%s' is too long\n", pszFilename);
-                rcExit = RTEXITCODE_FAILURE;
-            }
-            else
-            {
-                unsigned i;
-                for (i = 0; i < cbFile && !RT_C_IS_CNTRL(szPasswd[i]); i++)
-                    ;
-                szPasswd[i] = '\0';
-                *pPasswd = szPasswd;
-            }
-        }
-        else
-        {
-            RTPrintf("Cannot read password from file '%s': %Rrc\n", pszFilename, vrc);
-            rcExit = RTEXITCODE_FAILURE;
-        }
-        if (!fStdIn)
-            RTStrmClose(pStrm);
-    }
-    else
-    {
-        RTPrintf("Cannot open password file '%s' (%Rrc)\n", pszFilename, vrc);
-        rcExit = RTEXITCODE_FAILURE;
-    }
-
-    return rcExit;
-}
-
-static RTEXITCODE settingsPasswordFile(ComPtr<IVirtualBox> virtualBox, const char *pszFilename)
-{
-    com::Utf8Str passwd;
-    RTEXITCODE rcExit = readPasswordFile(pszFilename, &passwd);
-    if (rcExit == RTEXITCODE_SUCCESS)
-    {
-        int rc;
-        CHECK_ERROR(virtualBox, SetSettingsSecret(com::Bstr(passwd).raw()));
-        if (FAILED(rc))
-            rcExit = RTEXITCODE_FAILURE;
-    }
-
-    return rcExit;
 }
 
Index: /trunk/src/VBox/Main/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Main/Makefile.kmk	(revision 80568)
+++ /trunk/src/VBox/Main/Makefile.kmk	(revision 80569)
@@ -385,4 +385,13 @@
 VBoxSDS_TEMPLATE = VBOXMAINEXE
 VBoxSDS_DEFS += VBOX_COM_OUTOFPROC_MODULE _WIN32_WINNT=0x0600
+ ifdef VBOX_WITH_VBOXSDL
+VBoxSDS_DEFS += VBOX_WITH_VBOXSDL
+ endif
+ ifdef VBOX_WITH_HEADLESS
+VBoxSDS_DEFS += VBOX_WITH_HEADLESS
+ endif
+ ifdef VBOX_WITH_QTGUI
+VBoxSDS_DEFS += VBOX_WITH_QTGUI
+ endif
 VBoxSDS_INCS  = \
 	include \
@@ -394,5 +403,6 @@
 	src-global/win/VBoxSDS.cpp \
 	src-global/win/VirtualBoxSDSImpl.cpp \
-	src-global/win/VBoxSDS.rc
+	src-global/win/VBoxSDS.rc \
+	src-all/MachineLaunchVMCommonWorker.cpp
 $(call KB_FN_DO_PASS0_ON_TARGET,VBoxSDS) # Sets VBoxSDS_0_OUTDIR
 
@@ -553,4 +563,5 @@
 	src-server/HostVideoInputDeviceImpl.cpp \
 	src-server/MachineImpl.cpp \
+	src-all/MachineLaunchVMCommonWorker.cpp \
 	src-server/MachineImplCloneVM.cpp \
 	src-server/MachineImplMoveVM.cpp \
Index: /trunk/src/VBox/Main/idl/VirtualBox.xidl
===================================================================
--- /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 80568)
+++ /trunk/src/VBox/Main/idl/VirtualBox.xidl	(revision 80569)
@@ -27033,5 +27033,5 @@
   <interface
     name="IVirtualBoxSDS" extends="$unknown" notdual="yes"
-    uuid="152265b8-fe7d-4077-9dd6-032bc3f1c5a3"
+    uuid="bc1a2773-18f2-4066-08ce-1e44d59d84af"
     wsmap="suppress" internal="yes"
     reservedMethods="0" reservedAttributes="0"
@@ -27068,4 +27068,75 @@
         <param name="pid" type="long" dir="in">
           <desc>The process ID of the VBoxSVC instance (same as during registration).</desc>
+        </param>
+      </method>
+
+      <method name="launchVMProcess">
+        <desc>
+          Spawns a new process that will execute the virtual machine in the interactive
+          windows session of calling user. Any additional checks are performed by created
+          process itself
+
+          If launching the VM succeeds, the new VM process will create its own session
+          and write-lock the machine for it, preventing conflicting changes from other
+          processes. If the machine is already locked (because it is already running or
+          because another session has a write lock), launching the VM process will therefore
+          fail. Reversely, future attempts to obtain a write lock will also fail while the
+          machine is running.
+
+          Launching a VM process can take some time (a new VM is started in a new process,
+          for which memory and other resources need to be set up) but the method does
+          not wait for completion and just returns the PID of created process.
+
+          <result name="E_INVALIDARG">
+            Some of the parameters are invalid.
+          </result>
+          <result name="VBOX_E_IPRT_ERROR">
+            Launching process for machine failed.
+          </result>
+        </desc>
+        <param name="machine" type="wstring" dir="in">
+          <desc>
+            The name or id of the machine the VM will start for.
+          </desc>
+        </param>
+        <param name="comment" type="wstring" dir="in">
+          <desc>
+            The comment for VM.
+          </desc>
+        </param>
+        <param name="frontend" type="wstring" dir="in">
+          <desc>
+            Front-end to use for the new VM process. The following are currently supported:
+            <ul>
+              <li><tt>"gui"</tt>: VirtualBox Qt GUI front-end</li>
+              <li><tt>"headless"</tt>: VBoxHeadless (VRDE Server) front-end</li>
+              <li><tt>"sdl"</tt>: VirtualBox SDL front-end</li>
+              <li><tt>""</tt>: use the per-VM default frontend if set, otherwise
+                the global default defined in the system properties. If neither
+                are set, the API will launch a <tt>"gui"</tt> session, which may
+                fail if there is no windowing environment available. See
+                <link to="IMachine::defaultFrontend"/> and
+                <link to="ISystemProperties::defaultFrontend"/>.</li>
+            </ul>
+          </desc>
+        </param>
+        <param name="environmentChanges" type="wstring" dir="in">
+          <desc>
+            Environment changes to pass to the VM process, putenv style using newline as separator.
+            <!-- TODO: make this a safearray so values can safely contain newlines and '\'. -->
+          </desc>
+        </param>
+        <param name="cmdOptions" type="wstring" dir="in">
+          <desc>
+            Additional command line options to pass to the VM process.
+          </desc>
+        </param>
+        <param name="sessionId" type="unsigned long" dir="in">
+          <desc>
+            Windows session where the VM process should be launched.
+          </desc>
+        </param>
+        <param name="pid" type="unsigned long" dir="return">
+          <desc>The PID of created process.</desc>
         </param>
       </method>
Index: /trunk/src/VBox/Main/include/MachineLaunchVMCommonWorker.h
===================================================================
--- /trunk/src/VBox/Main/include/MachineLaunchVMCommonWorker.h	(revision 80569)
+++ /trunk/src/VBox/Main/include/MachineLaunchVMCommonWorker.h	(revision 80569)
@@ -0,0 +1,38 @@
+/* $Id$ */
+/** @file
+ * VirtualBox Main - VM process launcher helper for VBoxSVC & VBoxSDS.
+ */
+
+/*
+ * Copyright (C) 2011-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+#ifndef MAIN_INCLUDED_MachineLaunchVMCommonWorker_h
+#define MAIN_INCLUDED_MachineLaunchVMCommonWorker_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include "VirtualBoxBase.h"
+
+int MachineLaunchVMCommonWorker(const Utf8Str &aNameOrId,
+                                const Utf8Str &aComment,
+                                const Utf8Str &aFrontend,
+                                const Utf8Str &aEnvironment,
+                                const Utf8Str &aExtraArg,
+                                const Utf8Str &aFilename,
+                                uint32_t      aFlags,
+                                void         *aExtraData,
+                                RTPROCESS     &aPid);
+
+#endif /* !MAIN_INCLUDED_MachineLaunchVMCommonWorker_h */
+/* vi: set tabstop=4 shiftwidth=4 expandtab: */
+
Index: /trunk/src/VBox/Main/include/VirtualBoxSDSImpl.h
===================================================================
--- /trunk/src/VBox/Main/include/VirtualBoxSDSImpl.h	(revision 80568)
+++ /trunk/src/VBox/Main/include/VirtualBoxSDSImpl.h	(revision 80569)
@@ -94,4 +94,6 @@
     STDMETHOD(RegisterVBoxSVC)(IVBoxSVCRegistration *aVBoxSVC, LONG aPid, IUnknown **aExistingVirtualBox);
     STDMETHOD(DeregisterVBoxSVC)(IVBoxSVCRegistration *aVBoxSVC, LONG aPid);
+    STDMETHOD(LaunchVMProcess)(IN_BSTR aMachine, IN_BSTR aComment, IN_BSTR aFrontend, IN_BSTR aEnvironmentChanges,
+                               IN_BSTR aCmdOptions, ULONG aSessionId, ULONG *aPid);
     /** @} */
 
Index: /trunk/src/VBox/Main/src-all/ExtPackManagerImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-all/ExtPackManagerImpl.cpp	(revision 80568)
+++ /trunk/src/VBox/Main/src-all/ExtPackManagerImpl.cpp	(revision 80569)
@@ -2508,4 +2508,5 @@
                          NULL /*pszAsUser*/,
                          NULL /*pszPassword*/,
+                         NULL /*pvExtraData*/,
                          &hProcess);
     if (RT_SUCCESS(vrc))
Index: /trunk/src/VBox/Main/src-all/MachineLaunchVMCommonWorker.cpp
===================================================================
--- /trunk/src/VBox/Main/src-all/MachineLaunchVMCommonWorker.cpp	(revision 80569)
+++ /trunk/src/VBox/Main/src-all/MachineLaunchVMCommonWorker.cpp	(revision 80569)
@@ -0,0 +1,312 @@
+/* $Id$ */
+/** @file
+ * VirtualBox Main - VM process launcher helper for VBoxSVC & VBoxSDS.
+ */
+
+/*
+ * Copyright (C) 2011-2019 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include <iprt/process.h>
+#include <iprt/log.h>
+#include <iprt/path.h>
+#include <iprt/env.h>
+#include <iprt/file.h>
+#include <iprt/dir.h>
+#include "MachineLaunchVMCommonWorker.h"
+
+
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+# define HOSTSUFF_EXE ".exe"
+#else
+# define HOSTSUFF_EXE ""
+#endif
+
+
+/**
+ * Launch a VM process.
+ *
+ * The function starts the new VM process. It is a caller's responsibility
+ * to make any checks before and after calling the function.
+ * The function is a part of both VBoxSVC and VBoxSDS, so any calls to IVirtualBox
+ * and IMachine interfaces are performed using the client API.
+ *
+ * @returns VBox status code.
+ * @retval  VINF_SUCCESS when new VM process started.
+ * @retval  VERR_INVALID_PARAMETER when either aMachine is not Machine interface
+ *          or invalid aFrontend is specified.  Hmm. Come to think of it, it
+ *          could also be returned in some other cases, especially if the code
+ *          is buggy, so I wouldn't rely on any exact meaning here!
+ * @retval  VERR_INTERNAL_ERROR when something wrong.
+ *
+ * @param   aNameOrId        The Machine name or id interface the VM will start for.
+ * @param   aComment         The comment for new VM process.
+ * @param   aFrontend        The desired frontend for started VM.
+ * @param   aEnvironment     Additional environment variables=value pairs
+ *                           separated by newlines for new VM process.
+ * @param   aExtraArg        Extra argument for the VM process.  Ignored if
+ *                           empty string.
+ * @param   aFilename        Start new VM using specified filename. Only filename
+ *                           without path is allowed. Default filename is used if
+ *                           empty.
+ * @param   aFlags           Flags for RTProcCreateEx functions family if
+ *                           required (RTPROC_FLAGS_XXX).
+ * @param   aExtraData       Additional data for RTProcCreateX functions family
+ *                           if required.  Content is defined by the flags.
+ * @param   aPid             The PID of created process is returned here
+ */
+int MachineLaunchVMCommonWorker(const Utf8Str &aNameOrId,
+                                const Utf8Str &aComment,
+                                const Utf8Str &aFrontend,
+                                const Utf8Str &aEnvironment,
+                                const Utf8Str &aExtraArg,
+                                const Utf8Str &aFilename,
+                                uint32_t      aFlags,
+                                void         *aExtraData,
+                                RTPROCESS     &aPid)
+{
+    NOREF(aNameOrId);
+    NOREF(aComment);
+    NOREF(aFlags);
+    NOREF(aExtraData);
+    NOREF(aExtraArg);
+    NOREF(aFilename);
+
+    /* Get the path to the executable directory: */
+    char szPath[RTPATH_MAX];
+    RTPathAppPrivateArch(szPath, sizeof(szPath) - 1);
+    size_t cbBufLeft = strlen(szPath);
+    szPath[cbBufLeft++] = RTPATH_DELIMITER;
+    szPath[cbBufLeft] = '\0';
+    char *pszNamePart = &szPath[cbBufLeft]; NOREF(pszNamePart);
+    cbBufLeft = sizeof(szPath) - cbBufLeft;
+
+    /* The process started when launching a VM with separate UI/VM processes is always
+     * the UI process, i.e. needs special handling as it won't claim the session. */
+    bool fSeparate = aFrontend.endsWith("separate", Utf8Str::CaseInsensitive); NOREF(fSeparate);
+
+    aPid = NIL_RTPROCESS;
+
+    RTENV hEnv = RTENV_DEFAULT;
+    int vrc = VINF_SUCCESS;
+    if (!aEnvironment.isEmpty())
+    {
+        Utf8Str strEnvCopy(aEnvironment); /* auto release trick */
+
+#ifdef IN_VBOXSVC
+        /* VBoxSVC: clone the current environment */
+        vrc = RTEnvClone(&hEnv, RTENV_DEFAULT);
+#else
+        /* VBoxSDS: Create a change record environment since RTProcCreateEx has to
+                    build the final environment from the profile of the VBoxSDS caller. */
+        aFlags |= RTPROC_FLAGS_ENV_CHANGE_RECORD;
+        vrc = RTEnvCreateChangeRecord(&hEnv);
+#endif
+        AssertRCReturn(vrc, vrc);
+
+        /* Apply the specified environment changes (ignoring empty variable names
+           as RTEnv intentionally does not support that). */
+        char *pszEnvMutable = strEnvCopy.mutableRaw();
+        char *pszVar = pszEnvMutable;
+        for (char *psz = pszEnvMutable; ; ++psz)
+        {
+            /** @todo r=bird: Broken escaping rule, how to end a variable with '\\'?
+              * E.g. TMP=C:\TEMP\  */
+            char const ch = *psz;
+            if (   (ch == '\n' && (psz == pszEnvMutable || psz[-1] != '\\'))
+                || ch == '\0')
+            {
+                *psz = '\0';
+                if (*pszVar)
+                {
+                    char *val = strchr(pszVar, '=');
+                    if (val)
+                    {
+                        *val++ = '\0';
+                        vrc = RTEnvSetEx(hEnv, pszVar, val);
+                    }
+                    else
+                        vrc = RTEnvUnsetEx(hEnv, pszVar);
+                    if (RT_FAILURE(vrc))
+                    {
+                        RTEnvDestroy(hEnv);
+                        return vrc;
+                    }
+                }
+                if (!ch)
+                    break;
+                pszVar = psz + 1;
+            }
+        }
+    }
+
+#ifdef VBOX_WITH_QTGUI
+    if (   !aFrontend.compare("gui", Utf8Str::CaseInsensitive)
+        || !aFrontend.compare("GUI/Qt", Utf8Str::CaseInsensitive)
+        || !aFrontend.compare("separate", Utf8Str::CaseInsensitive)
+        || !aFrontend.compare("gui/separate", Utf8Str::CaseInsensitive)
+        || !aFrontend.compare("GUI/Qt/separate", Utf8Str::CaseInsensitive))
+    {
+# ifdef RT_OS_DARWIN /* Avoid Launch Services confusing this with the selector by using a helper app. */
+        /* Modify the base path so that we don't need to use ".." below. */
+        RTPathStripTrailingSlash(szPath);
+        RTPathStripFilename(szPath);
+        cbBufLeft = strlen(szPath);
+        pszNamePart = szPath + cbBufLeft;
+        cbBufLeft = sizeof(szPath) - cbBufLeft;
+
+#  define OSX_APP_NAME "VirtualBoxVM"
+#  define OSX_APP_PATH_FMT "/Resources/%s.app/Contents/MacOS/VirtualBoxVM"
+
+        Utf8Str strAppOverride = aFilename;
+        if (   strAppOverride.contains(".")
+            || strAppOverride.contains("/")
+            || strAppOverride.contains("\\")
+            || strAppOverride.contains(":"))
+            strAppOverride.setNull();
+        Utf8Str strAppPath;
+        if (!strAppOverride.isEmpty())
+        {
+            strAppPath = Utf8StrFmt(OSX_APP_PATH_FMT, strAppOverride.c_str());
+            Utf8Str strFullPath(szPath);
+            strFullPath.append(strAppPath);
+            /* there is a race, but people using this deserve the failure */
+            if (!RTFileExists(strFullPath.c_str()))
+                strAppOverride.setNull();
+        }
+        if (strAppOverride.isEmpty())
+            strAppPath = Utf8StrFmt(OSX_APP_PATH_FMT, OSX_APP_NAME);
+        vrc = RTStrCopy(pszNamePart, cbBufLeft, strAppPath.c_str());
+        AssertReturn(vrc, vrc);
+# else
+        static const char s_szVirtualBox_exe[] = "VirtualBoxVM" HOSTSUFF_EXE;
+        vrc = RTStrCopy(pszNamePart, cbBufLeft, s_szVirtualBox_exe);
+        AssertRCReturn(vrc, vrc);
+# endif
+
+        const char *apszArgs[] =
+        {
+            szPath,
+            "--comment", aComment.c_str(),
+            "--startvm", aNameOrId.c_str(),
+            "--no-startvm-errormsgbox",
+            NULL, /* For "--separate". */
+            NULL, /* For "--sup-startup-log". */
+            NULL
+        };
+        unsigned iArg = 6;
+        if (fSeparate)
+            apszArgs[iArg++] = "--separate";
+        if (aExtraArg.isNotEmpty())
+            apszArgs[iArg++] = aExtraArg.c_str();
+
+        vrc = RTProcCreateEx(szPath, apszArgs, hEnv, aFlags, NULL, NULL, NULL, NULL, NULL, aExtraData, &aPid);
+    }
+#else /* !VBOX_WITH_QTGUI */
+    if (0)
+        ;
+#endif /* VBOX_WITH_QTGUI */
+
+    else
+
+#ifdef VBOX_WITH_VBOXSDL
+    if (   !aFrontend.compare("sdl", Utf8Str::CaseInsensitive)
+        || !aFrontend.compare("GUI/SDL", Utf8Str::CaseInsensitive)
+        || !aFrontend.compare("sdl/separate", Utf8Str::CaseInsensitive)
+        || !aFrontend.compare("GUI/SDL/separate", Utf8Str::CaseInsensitive))
+    {
+        static const char s_szVBoxSDL_exe[] = "VBoxSDL" HOSTSUFF_EXE;
+        vrc = RTStrCopy(pszNamePart, cbBufLeft, s_szVBoxSDL_exe);
+        AssertRCReturn(vrc, vrc);
+
+        const char *apszArgs[] =
+        {
+            szPath,
+            "--comment", aComment.c_str(),
+            "--startvm", aNameOrId.c_str(),
+            NULL, /* For "--separate". */
+            NULL, /* For "--sup-startup-log". */
+            NULL
+        };
+        unsigned iArg = 5;
+        if (fSeparate)
+            apszArgs[iArg++] = "--separate";
+        if (aExtraArg.isNotEmpty())
+            apszArgs[iArg++] = aExtraArg.c_str();
+
+        vrc = RTProcCreateEx(szPath, apszArgs, hEnv, aFlags, NULL, NULL, NULL, NULL, NULL, aExtraData, &aPid);
+    }
+#else /* !VBOX_WITH_VBOXSDL */
+    if (0)
+        ;
+#endif /* !VBOX_WITH_VBOXSDL */
+
+    else
+
+#ifdef VBOX_WITH_HEADLESS
+    if (   !aFrontend.compare("headless", Utf8Str::CaseInsensitive)
+        || !aFrontend.compare("capture", Utf8Str::CaseInsensitive)
+        || !aFrontend.compare("vrdp", Utf8Str::CaseInsensitive) /* Deprecated. Same as headless. */
+       )
+    {
+        /* On pre-4.0 the "headless" type was used for passing "--vrdp off" to VBoxHeadless to let it work in OSE,
+         * which did not contain VRDP server. In VBox 4.0 the remote desktop server (VRDE) is optional,
+         * and a VM works even if the server has not been installed.
+         * So in 4.0 the "headless" behavior remains the same for default VBox installations.
+         * Only if a VRDE has been installed and the VM enables it, the "headless" will work
+         * differently in 4.0 and 3.x.
+         */
+        static const char s_szVBoxHeadless_exe[] = "VBoxHeadless" HOSTSUFF_EXE;
+        vrc = RTStrCopy(pszNamePart, cbBufLeft, s_szVBoxHeadless_exe);
+        AssertRCReturn(vrc, vrc);
+
+        const char *apszArgs[] =
+        {
+            szPath,
+            "--comment", aComment.c_str(),
+            "--startvm", aNameOrId.c_str(),
+            "--vrde", "config",
+            NULL, /* For "--capture". */
+            NULL, /* For "--sup-startup-log". */
+            NULL
+        };
+        unsigned iArg = 7;
+        if (!aFrontend.compare("capture", Utf8Str::CaseInsensitive))
+            apszArgs[iArg++] = "--capture";
+        if (aExtraArg.isNotEmpty())
+            apszArgs[iArg++] = aExtraArg.c_str();
+
+# ifdef RT_OS_WINDOWS
+        aFlags |= RTPROC_FLAGS_NO_WINDOW;
+# endif
+        vrc = RTProcCreateEx(szPath, apszArgs, hEnv, aFlags, NULL, NULL, NULL, NULL, NULL, aExtraData, &aPid);
+    }
+#else /* !VBOX_WITH_HEADLESS */
+    if (0)
+        ;
+#endif /* !VBOX_WITH_HEADLESS */
+    else
+        vrc = VERR_INVALID_PARAMETER;
+
+    RTEnvDestroy(hEnv);
+
+    if (RT_FAILURE(vrc))
+        return vrc;
+
+    return VINF_SUCCESS;
+}
Index: /trunk/src/VBox/Main/src-client/ClientTokenHolder.cpp
===================================================================
--- /trunk/src/VBox/Main/src-client/ClientTokenHolder.cpp	(revision 80568)
+++ /trunk/src/VBox/Main/src-client/ClientTokenHolder.cpp	(revision 80569)
@@ -250,7 +250,9 @@
     HANDLE initDoneSem = (HANDLE)data[1];
 
-    HANDLE mutex = ::OpenMutex(MUTEX_ALL_ACCESS, FALSE, Bstr(strSessionId).raw());
-    AssertMsg(mutex, ("cannot open token, err=%d\n", ::GetLastError()));
-
+    Bstr bstrSessionId(strSessionId);
+    HANDLE mutex = ::OpenMutex(MUTEX_ALL_ACCESS, FALSE, bstrSessionId.raw());
+
+    //AssertMsg(mutex, ("cannot open token, err=%u\n", ::GetLastError()));
+    AssertMsg(mutex, ("cannot open token %ls, err=%u\n", bstrSessionId.raw(), ::GetLastError()));
     if (mutex)
     {
Index: /trunk/src/VBox/Main/src-global/win/VirtualBoxSDSImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-global/win/VirtualBoxSDSImpl.cpp	(revision 80568)
+++ /trunk/src/VBox/Main/src-global/win/VirtualBoxSDSImpl.cpp	(revision 80569)
@@ -31,4 +31,5 @@
 #include <iprt/critsect.h>
 #include <iprt/mem.h>
+#include <iprt/process.h>
 #include <iprt/system.h>
 
@@ -37,4 +38,15 @@
 #include <sddl.h>
 #include <lmcons.h> /* UNLEN */
+
+#include "MachineLaunchVMCommonWorker.h"
+
+
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
+#define INTERACTIVE_SID_FLAG 0x1
+#define LOCAL_SID_FLAG       0x2
+#define LOGON_SID_FLAG       0x4
+#define IS_INTERACTIVE       (LOCAL_SID_FLAG|INTERACTIVE_SID_FLAG|LOGON_SID_FLAG)
 
 
@@ -388,4 +400,62 @@
         hrc = E_INVALIDARG;
     LogRel2(("VirtualBoxSDS::deregisterVBoxSVC: returns %Rhrc\n", hrc));
+    return hrc;
+}
+
+
+STDMETHODIMP VirtualBoxSDS::LaunchVMProcess(IN_BSTR aMachine, IN_BSTR aComment, IN_BSTR aFrontend, IN_BSTR aEnvironmentChanges,
+                                            IN_BSTR aCmdOptions, ULONG aSessionId, ULONG *aPid)
+{
+    /*
+     * Convert parameters to UTF-8.
+     */
+    Utf8Str strMachine(aMachine);
+    Utf8Str strComment(aComment);
+    Utf8Str strFrontend(aFrontend);
+    Utf8Str strEnvironmentChanges(aEnvironmentChanges);
+    Utf8Str strCmdOptions(aCmdOptions);
+
+    /*
+     * Impersonate the caller.
+     */
+    HRESULT hrc = CoImpersonateClient();
+    if (SUCCEEDED(hrc))
+    {
+        try
+        {
+            /*
+             * Try launch the VM process as the client.
+             */
+            RTPROCESS pid;
+            AssertCompile(sizeof(aSessionId) == sizeof(uint32_t));
+            int vrc = ::MachineLaunchVMCommonWorker(strMachine, strComment, strFrontend, strEnvironmentChanges,
+                                                    strCmdOptions, Utf8Str(),
+                                                    RTPROC_FLAGS_AS_IMPERSONATED_TOKEN | RTPROC_FLAGS_SERVICE
+                                                    | RTPROC_FLAGS_PROFILE | RTPROC_FLAGS_DESIRED_SESSION_ID,
+                                                    &aSessionId, pid);
+            if (RT_SUCCESS(vrc))
+            {
+                *aPid = (ULONG)pid;
+                LogRel(("VirtualBoxSDS::LaunchVMProcess: launchVM succeeded\n"));
+            }
+            else if (vrc == VERR_INVALID_PARAMETER)
+            {
+                hrc = E_INVALIDARG;
+                LogRel(("VirtualBoxSDS::LaunchVMProcess: launchVM failed: %Rhrc\n", hrc));
+            }
+            else
+            {
+                hrc = VBOX_E_IPRT_ERROR;
+                LogRel(("VirtualBoxSDS::LaunchVMProcess: launchVM failed: %Rhrc (%Rrc)\n", hrc));
+            }
+        }
+        catch (...)
+        {
+            hrc = E_UNEXPECTED;
+        }
+        CoRevertToSelf();
+    }
+    else
+        LogRel(("VirtualBoxSDS::LaunchVMProcess: CoImpersonateClient failed: %Rhrc\n", hrc));
     return hrc;
 }
@@ -592,4 +662,5 @@
 }
 
+
 #ifdef WITH_WATCHER
 /**
Index: /trunk/src/VBox/Main/src-helper-apps/VBoxExtPackHelperApp.cpp
===================================================================
--- /trunk/src/VBox/Main/src-helper-apps/VBoxExtPackHelperApp.cpp	(revision 80568)
+++ /trunk/src/VBox/Main/src-helper-apps/VBoxExtPackHelperApp.cpp	(revision 80569)
@@ -1548,6 +1548,6 @@
          */
         RTPROCESS hProcess;
-        rc = RTProcCreateEx(papszArgs[iSuArg], &papszArgs[iSuArg], RTENV_DEFAULT, 0 /*fFlags*/,
-                            NULL /*phStdIn*/, NULL /*phStdOut*/, NULL /*phStdErr*/, NULL /*pszAsUser*/, NULL /*pszPassword*/,
+        rc = RTProcCreateEx(papszArgs[iSuArg], &papszArgs[iSuArg], RTENV_DEFAULT, 0 /*fFlags*/, NULL /*phStdIn*/,
+                            NULL /*phStdOut*/, NULL /*phStdErr*/, NULL /*pszAsUser*/, NULL /*pszPassword*/, NULL /* pvExtraData*/,
                             &hProcess);
         if (RT_SUCCESS(rc))
Index: /trunk/src/VBox/Main/src-server/ClientToken.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/ClientToken.cpp	(revision 80568)
+++ /trunk/src/VBox/Main/src-server/ClientToken.cpp	(revision 80569)
@@ -40,4 +40,8 @@
 #include "ClientToken.h"
 #include "MachineImpl.h"
+
+#ifdef RT_OS_WINDOWS
+# include <sddl.h>
+#endif
 
 Machine::ClientToken::ClientToken()
@@ -83,13 +87,77 @@
 #if defined(RT_OS_WINDOWS)
     NOREF(pSessionMachine);
-    Bstr tokenId = pMachine->mData->m_strConfigFileFull;
-    for (size_t i = 0; i < tokenId.length(); i++)
-        if (tokenId.raw()[i] == '\\')
-            tokenId.raw()[i] = '/';
-    mClientToken = ::CreateMutex(NULL, FALSE, tokenId.raw());
+
+    /* Get user's SID to use it as part of the mutex name to distinguish shared machine instances
+     * between users
+     */
+    Utf8Str strUserSid;
+    HANDLE  hProcessToken = INVALID_HANDLE_VALUE;
+    if (::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &hProcessToken))
+    {
+        DWORD dwSize = 0;
+        BOOL fRc = ::GetTokenInformation(hProcessToken, TokenUser, NULL, 0, &dwSize);
+        DWORD dwErr = ::GetLastError();
+        if (!fRc && dwErr == ERROR_INSUFFICIENT_BUFFER && dwSize > 0)
+        {
+            PTOKEN_USER pTokenUser = (PTOKEN_USER)RTMemTmpAllocZ(dwSize);
+            if (pTokenUser)
+            {
+                if (::GetTokenInformation(hProcessToken, TokenUser, pTokenUser, dwSize, &dwSize))
+                {
+                    PRTUTF16 wstrSid = NULL;
+                    if (::ConvertSidToStringSid(pTokenUser->User.Sid, &wstrSid))
+                    {
+                        strUserSid = wstrSid;
+                        ::LocalFree(wstrSid);
+                    }
+                    else
+                        AssertMsgFailed(("Cannot convert SID to string, err=%u", ::GetLastError()));
+                }
+                else
+                    AssertMsgFailed(("Cannot get thread access token information, err=%u", ::GetLastError()));
+                RTMemFree(pTokenUser);
+            }
+            else
+                AssertMsgFailed(("No memory"));
+        }
+        else
+            AssertMsgFailed(("Cannot get thread access token information, err=%u", ::GetLastError()));
+        CloseHandle(hProcessToken);
+    }
+    else
+        AssertMsgFailed(("Cannot get thread access token, err=%u", ::GetLastError()));
+
+    Bstr tokenId = Bstr(Utf8Str("Global\\") + strUserSid + "/" + pMachine->mData->mUuid.toString());
+
+    /* create security descriptor to allow SYNCHRONIZE access from any windows sessions and users.
+     * otherwise VM can't open the mutex if VBoxSVC and VM are in different session (e.g. some VM
+     * started by autostart service)
+     *
+     * SDDL string contains following ACEs:
+     *   CreateOwner           : MUTEX_ALL_ACCESS
+     *   System                : MUTEX_ALL_ACCESS
+     *   BuiltInAdministrators : MUTEX_ALL_ACCESS
+     *   Everyone              : SYNCHRONIZE|MUTEX_MODIFY_STATE
+     */
+
+    //static const RTUTF16 s_wszSecDesc[] = L"D:(A;;0x1F0001;;;CO)(A;;0x1F0001;;;SY)(A;;0x1F0001;;;BA)(A;;0x100001;;;WD)";
+    com::BstrFmt bstrSecDesc("O:%sD:(A;;0x1F0001;;;CO)(A;;0x1F0001;;;SY)(A;;0x1F0001;;;BA)", strUserSid.c_str());
+    PSECURITY_DESCRIPTOR pSecDesc = NULL;
+    //AssertMsgStmt(::ConvertStringSecurityDescriptorToSecurityDescriptor(s_wszSecDesc, SDDL_REVISION_1, &pSecDesc, NULL),
+    AssertMsgStmt(::ConvertStringSecurityDescriptorToSecurityDescriptor(bstrSecDesc.raw(), SDDL_REVISION_1, &pSecDesc, NULL),
+                  ("Cannot create security descriptor for token '%ls', err=%u", tokenId.raw(), GetLastError()),
+                  pSecDesc = NULL);
+
+    SECURITY_ATTRIBUTES SecAttr;
+    SecAttr.lpSecurityDescriptor = pSecDesc;
+    SecAttr.nLength              = sizeof(SecAttr);
+    SecAttr.bInheritHandle       = FALSE;
+    mClientToken = ::CreateMutex(&SecAttr, FALSE, tokenId.raw());
     mClientTokenId = tokenId;
-    AssertMsg(mClientToken,
-              ("Cannot create token '%s', err=%d",
-               mClientTokenId.c_str(), ::GetLastError()));
+    AssertMsg(mClientToken, ("Cannot create token '%s', err=%d", mClientTokenId.c_str(), ::GetLastError()));
+
+    if (pSecDesc)
+        ::LocalFree(pSecDesc);
+
 #elif defined(RT_OS_OS2)
     NOREF(pSessionMachine);
Index: /trunk/src/VBox/Main/src-server/MachineImpl.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/MachineImpl.cpp	(revision 80568)
+++ /trunk/src/VBox/Main/src-server/MachineImpl.cpp	(revision 80569)
@@ -49,4 +49,5 @@
 #include "MachineImplMoveVM.h"
 #include "ExtPackManagerImpl.h"
+#include "MachineLaunchVMCommonWorker.h"
 
 // generated header
@@ -7409,67 +7410,4 @@
     }
 
-    /* get the path to the executable */
-    char szPath[RTPATH_MAX];
-    RTPathAppPrivateArch(szPath, sizeof(szPath) - 1);
-    size_t cchBufLeft = strlen(szPath);
-    szPath[cchBufLeft++] = RTPATH_DELIMITER;
-    szPath[cchBufLeft] = 0;
-    char *pszNamePart = szPath + cchBufLeft;
-    cchBufLeft = sizeof(szPath) - cchBufLeft;
-
-    int vrc = VINF_SUCCESS;
-    RTPROCESS pid = NIL_RTPROCESS;
-
-    RTENV env = RTENV_DEFAULT;
-
-    if (!strEnvironment.isEmpty())
-    {
-        char *newEnvStr = NULL;
-
-        do
-        {
-            /* clone the current environment */
-            int vrc2 = RTEnvClone(&env, RTENV_DEFAULT);
-            AssertRCBreakStmt(vrc2, vrc = vrc2);
-
-            newEnvStr = RTStrDup(strEnvironment.c_str());
-            AssertPtrBreakStmt(newEnvStr, vrc = vrc2);
-
-            /* put new variables to the environment
-             * (ignore empty variable names here since RTEnv API
-             * intentionally doesn't do that) */
-            char *var = newEnvStr;
-            for (char *p = newEnvStr; *p; ++p)
-            {
-                if (*p == '\n' && (p == newEnvStr || *(p - 1) != '\\'))
-                {
-                    *p = '\0';
-                    if (*var)
-                    {
-                        char *val = strchr(var, '=');
-                        if (val)
-                        {
-                            *val++ = '\0';
-                            vrc2 = RTEnvSetEx(env, var, val);
-                        }
-                        else
-                            vrc2 = RTEnvUnsetEx(env, var);
-                        if (RT_FAILURE(vrc2))
-                            break;
-                    }
-                    var = p + 1;
-                }
-            }
-            if (RT_SUCCESS(vrc2) && *var)
-                vrc2 = RTEnvPutEx(env, var);
-
-            AssertRCBreakStmt(vrc2, vrc = vrc2);
-        }
-        while (0);
-
-        if (newEnvStr != NULL)
-            RTStrFree(newEnvStr);
-    }
-
     /* Hardening logging */
 #if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_HARDENING)
@@ -7493,176 +7431,194 @@
         RTFileDelete(strOldStartupLogFile.c_str());
     }
-    const char *pszSupHardeningLogArg = strSupHardeningLogArg.c_str();
 #else
-    const char *pszSupHardeningLogArg = NULL;
+    Utf8Str strSupHardeningLogArg;
 #endif
 
+    Utf8Str strAppOverride;
+#ifdef RT_OS_DARWIN /* Avoid Launch Services confusing this with the selector by using a helper app. */
+    strAppOverride = i_getExtraData(Utf8Str("VBoxInternal2/VirtualBoxVMAppOverride"));
+#endif
+
+    bool fUseVBoxSDS = false;
     Utf8Str strCanonicalName;
-
+    if (false)
+    { }
 #ifdef VBOX_WITH_QTGUI
-    if (   !strFrontend.compare("gui", Utf8Str::CaseInsensitive)
-        || !strFrontend.compare("GUI/Qt", Utf8Str::CaseInsensitive)
-        || !strFrontend.compare("separate", Utf8Str::CaseInsensitive)
-        || !strFrontend.compare("gui/separate", Utf8Str::CaseInsensitive)
-        || !strFrontend.compare("GUI/Qt/separate", Utf8Str::CaseInsensitive))
+    else if (   !strFrontend.compare("gui", Utf8Str::CaseInsensitive)
+             || !strFrontend.compare("GUI/Qt", Utf8Str::CaseInsensitive)
+             || !strFrontend.compare("separate", Utf8Str::CaseInsensitive)
+             || !strFrontend.compare("gui/separate", Utf8Str::CaseInsensitive)
+             || !strFrontend.compare("GUI/Qt/separate", Utf8Str::CaseInsensitive))
     {
         strCanonicalName = "GUI/Qt";
-# ifdef RT_OS_DARWIN /* Avoid Launch Services confusing this with the selector by using a helper app. */
-        /* Modify the base path so that we don't need to use ".." below. */
-        RTPathStripTrailingSlash(szPath);
-        RTPathStripFilename(szPath);
-        cchBufLeft = strlen(szPath);
-        pszNamePart = szPath + cchBufLeft;
-        cchBufLeft = sizeof(szPath) - cchBufLeft;
-
-#  define OSX_APP_NAME "VirtualBoxVM"
-#  define OSX_APP_PATH_FMT "/Resources/%s.app/Contents/MacOS/VirtualBoxVM"
-
-        Utf8Str strAppOverride = i_getExtraData(Utf8Str("VBoxInternal2/VirtualBoxVMAppOverride"));
-        if (   strAppOverride.contains(".")
-            || strAppOverride.contains("/")
-            || strAppOverride.contains("\\")
-            || strAppOverride.contains(":"))
-            strAppOverride.setNull();
-        Utf8Str strAppPath;
-        if (!strAppOverride.isEmpty())
-        {
-            strAppPath = Utf8StrFmt(OSX_APP_PATH_FMT, strAppOverride.c_str());
-            Utf8Str strFullPath(szPath);
-            strFullPath.append(strAppPath);
-            /* there is a race, but people using this deserve the failure */
-            if (!RTFileExists(strFullPath.c_str()))
-                strAppOverride.setNull();
-        }
-        if (strAppOverride.isEmpty())
-            strAppPath = Utf8StrFmt(OSX_APP_PATH_FMT, OSX_APP_NAME);
-        AssertReturn(cchBufLeft > strAppPath.length(), E_UNEXPECTED);
-        strcpy(pszNamePart, strAppPath.c_str());
-# else
-        static const char s_szVirtualBox_exe[] = "VirtualBoxVM" HOSTSUFF_EXE;
-        Assert(cchBufLeft >= sizeof(s_szVirtualBox_exe));
-        strcpy(pszNamePart, s_szVirtualBox_exe);
-# endif
-
-        Utf8Str idStr = mData->mUuid.toString();
-        const char *apszArgs[] =
-        {
-            szPath,
-            "--comment", mUserData->s.strName.c_str(),
-            "--startvm", idStr.c_str(),
-            "--no-startvm-errormsgbox",
-            NULL, /* For "--separate". */
-            NULL, /* For "--sup-startup-log". */
-            NULL
-        };
-        unsigned iArg = 6;
-        if (fSeparate)
-            apszArgs[iArg++] = "--separate";
-        apszArgs[iArg++] = pszSupHardeningLogArg;
-
-        vrc = RTProcCreate(szPath, apszArgs, env, 0, &pid);
-    }
-#else /* !VBOX_WITH_QTGUI */
-    if (0)
-        ;
-#endif /* VBOX_WITH_QTGUI */
-
+        fUseVBoxSDS = true;
+    }
+#endif
+#ifdef VBOX_WITH_VBOXSDL
+    else if (   !strFrontend.compare("sdl", Utf8Str::CaseInsensitive)
+             || !strFrontend.compare("GUI/SDL", Utf8Str::CaseInsensitive)
+             || !strFrontend.compare("sdl/separate", Utf8Str::CaseInsensitive)
+             || !strFrontend.compare("GUI/SDL/separate", Utf8Str::CaseInsensitive))
+    {
+        strCanonicalName = "GUI/SDL";
+        fUseVBoxSDS = true;
+    }
+#endif
+#ifdef VBOX_WITH_HEADLESS
+    else if (   !strFrontend.compare("headless", Utf8Str::CaseInsensitive)
+             || !strFrontend.compare("capture", Utf8Str::CaseInsensitive)
+             || !strFrontend.compare("vrdp", Utf8Str::CaseInsensitive) /* Deprecated. Same as headless. */)
+    {
+        strCanonicalName = "headless";
+    }
+#endif
     else
-
-#ifdef VBOX_WITH_VBOXSDL
-    if (   !strFrontend.compare("sdl", Utf8Str::CaseInsensitive)
-        || !strFrontend.compare("GUI/SDL", Utf8Str::CaseInsensitive)
-        || !strFrontend.compare("sdl/separate", Utf8Str::CaseInsensitive)
-        || !strFrontend.compare("GUI/SDL/separate", Utf8Str::CaseInsensitive))
-    {
-        strCanonicalName = "GUI/SDL";
-        static const char s_szVBoxSDL_exe[] = "VBoxSDL" HOSTSUFF_EXE;
-        Assert(cchBufLeft >= sizeof(s_szVBoxSDL_exe));
-        strcpy(pszNamePart, s_szVBoxSDL_exe);
-
-        Utf8Str idStr = mData->mUuid.toString();
-        const char *apszArgs[] =
-        {
-            szPath,
-            "--comment", mUserData->s.strName.c_str(),
-            "--startvm", idStr.c_str(),
-            NULL, /* For "--separate". */
-            NULL, /* For "--sup-startup-log". */
-            NULL
-        };
-        unsigned iArg = 5;
-        if (fSeparate)
-            apszArgs[iArg++] = "--separate";
-        apszArgs[iArg++] = pszSupHardeningLogArg;
-
-        vrc = RTProcCreate(szPath, apszArgs, env, 0, &pid);
-    }
-#else /* !VBOX_WITH_VBOXSDL */
-    if (0)
-        ;
-#endif /* !VBOX_WITH_VBOXSDL */
-
+        return setError(E_INVALIDARG, tr("Invalid frontend name: '%s'"), strFrontend.c_str());
+
+    Utf8Str idStr = mData->mUuid.toString();
+    Utf8Str const &strMachineName = mUserData->s.strName;
+    RTPROCESS pid = NIL_RTPROCESS;
+
+#if !defined(VBOX_WITH_SDS) || !defined(RT_OS_WINDOWS)
+    RT_NOREF(fUseVBoxSDS);
+#else
+    DWORD idCallerSession = ~(DWORD)0;
+    if (fUseVBoxSDS)
+    {
+        /*
+         * The VBoxSDS should be used for process launching the VM with
+         * GUI only if the caller and the VBoxSDS are in different Windows
+         * sessions and the caller in the interactive one.
+         */
+        fUseVBoxSDS = false; 
+
+        /* Get windows session of the current process.  The process token used
+           due to several reasons:
+           1. The token is absent for the current thread except someone set it
+              for us.
+           2. Needs to get the id of the session where the process is started. 
+           We only need to do this once, though. */
+        static DWORD s_idCurrentSession = ~(DWORD)0;
+        DWORD idCurrentSession = s_idCurrentSession;
+        if (idCurrentSession == ~(DWORD)0)
+        {
+            HANDLE hCurrentProcessToken = NULL;
+            if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_READ, &hCurrentProcessToken))
+            {
+                DWORD cbIgn = 0;
+                if (GetTokenInformation(hCurrentProcessToken, TokenSessionId, &idCurrentSession, sizeof(idCurrentSession), &cbIgn))
+                    s_idCurrentSession = idCurrentSession;
+                else
+                {
+                    idCurrentSession = ~(DWORD)0;
+                    LogRelFunc(("GetTokenInformation/TokenSessionId on self failed: %u\n", GetLastError()));
+                }
+                CloseHandle(hCurrentProcessToken);
+            }
+            else
+                LogRelFunc(("OpenProcessToken/self failed: %u\n", GetLastError()));
+        }
+
+        /* get the caller's session */
+        HRESULT hrc = CoImpersonateClient();
+        if (SUCCEEDED(hrc))
+        {
+            HANDLE hCallerThreadToken;
+            if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_READ,
+                                FALSE /* OpenAsSelf - for impersonation at SecurityIdentification level */,
+                                &hCallerThreadToken))
+            {
+                SetLastError(NO_ERROR);
+                DWORD cbIgn = 0;
+                if (GetTokenInformation(hCallerThreadToken, TokenSessionId, &idCallerSession, sizeof(DWORD), &cbIgn))
+                {
+                    /* Only need to use SDS if the session ID differs: */
+                    if (idCurrentSession != idCallerSession)
+                    {
+                        fUseVBoxSDS = false;
+
+                        /* Obtain the groups the access token belongs to so we can see if the session is interactive: */
+                        DWORD         cbTokenGroups = 0;
+                        PTOKEN_GROUPS pTokenGroups  = NULL;
+                        if (   !GetTokenInformation(hCallerThreadToken, TokenGroups, pTokenGroups, 0, &cbTokenGroups)
+                            && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
+                            pTokenGroups = (PTOKEN_GROUPS)RTMemTmpAllocZ(cbTokenGroups);
+                        if (GetTokenInformation(hCallerThreadToken, TokenGroups, pTokenGroups, cbTokenGroups, &cbTokenGroups))
+                        {
+                            /* Well-known interactive SID: SECURITY_INTERACTIVE_RID, S-1-5-4: */
+                            SID_IDENTIFIER_AUTHORITY sidIdNTAuthority = SECURITY_NT_AUTHORITY;
+                            PSID                     pInteractiveSid = NULL;
+                            if (AllocateAndInitializeSid(&sidIdNTAuthority, 1, 4, 0, 0, 0, 0, 0, 0, 0, &pInteractiveSid))
+                            {
+                                /* Iterate over the groups looking for the interactive SID: */
+                                fUseVBoxSDS = false;
+                                for (DWORD dwIndex = 0; dwIndex < pTokenGroups->GroupCount; dwIndex++)
+                                    if (EqualSid(pTokenGroups->Groups[dwIndex].Sid, pInteractiveSid))
+                                    {
+                                        fUseVBoxSDS = true;
+                                        break;
+                                    }
+                                FreeSid(pInteractiveSid);
+                            }
+                        }
+                        else
+                            LogRelFunc(("GetTokenInformation/TokenGroups failed: %u\n", GetLastError()));
+                        RTMemTmpFree(pTokenGroups);
+                    }
+                }
+                else
+                    LogRelFunc(("GetTokenInformation/TokenSessionId failed: %u\n", GetLastError()));
+                CloseHandle(hCallerThreadToken);
+            }
+            else
+                LogRelFunc(("OpenThreadToken/client failed: %u\n", GetLastError()));
+            CoRevertToSelf();
+        }
+        else
+            LogRelFunc(("CoImpersonateClient failed: %Rhrc\n", hrc));
+    }
+    if (fUseVBoxSDS)
+    {
+        /* connect to VBoxSDS */
+        ComPtr<IVirtualBoxSDS> pVBoxSDS;
+        HRESULT rc = pVBoxSDS.createLocalObject(CLSID_VirtualBoxSDS);
+        if (FAILED(rc))
+            return setError(rc, tr("Failed to start the machine '%s'. A connection to VBoxSDS cannot be established"),
+                            strMachineName.c_str());
+
+        /* By default the RPC_C_IMP_LEVEL_IDENTIFY is used for impersonation the client. It allows
+           ACL checking but restricts an access to system objects e.g. files. Call to CoSetProxyBlanket
+           elevates the impersonation level up to RPC_C_IMP_LEVEL_IMPERSONATE allowing the VBoxSDS
+           service to access the files. */
+        rc = CoSetProxyBlanket(pVBoxSDS,
+                               RPC_C_AUTHN_DEFAULT,
+                               RPC_C_AUTHZ_DEFAULT,
+                               COLE_DEFAULT_PRINCIPAL,
+                               RPC_C_AUTHN_LEVEL_DEFAULT,
+                               RPC_C_IMP_LEVEL_IMPERSONATE,
+                               NULL,
+                               EOAC_DEFAULT);
+        if (FAILED(rc))
+            return setError(rc, tr("Failed to start the machine '%s'. CoSetProxyBlanket failed"), strMachineName.c_str());
+        ULONG uPid = 0;
+        rc = pVBoxSDS->LaunchVMProcess(Bstr(idStr).raw(), Bstr(strMachineName).raw(), Bstr(strFrontend).raw(),
+                                       Bstr(strEnvironment).raw(), Bstr(strSupHardeningLogArg).raw(),
+                                       idCallerSession, &uPid);
+        if (FAILED(rc))
+            return setError(rc, tr("Failed to start the machine '%s'. Process creation failed"), strMachineName.c_str());
+        pid = (RTPROCESS)uPid;
+    }
     else
-
-#ifdef VBOX_WITH_HEADLESS
-    if (   !strFrontend.compare("headless", Utf8Str::CaseInsensitive)
-        || !strFrontend.compare("capture", Utf8Str::CaseInsensitive)
-        || !strFrontend.compare("vrdp", Utf8Str::CaseInsensitive) /* Deprecated. Same as headless. */
-       )
-    {
-        strCanonicalName = "headless";
-        /* On pre-4.0 the "headless" type was used for passing "--vrdp off" to VBoxHeadless to let it work in OSE,
-         * which did not contain VRDP server. In VBox 4.0 the remote desktop server (VRDE) is optional,
-         * and a VM works even if the server has not been installed.
-         * So in 4.0 the "headless" behavior remains the same for default VBox installations.
-         * Only if a VRDE has been installed and the VM enables it, the "headless" will work
-         * differently in 4.0 and 3.x.
-         */
-        static const char s_szVBoxHeadless_exe[] = "VBoxHeadless" HOSTSUFF_EXE;
-        Assert(cchBufLeft >= sizeof(s_szVBoxHeadless_exe));
-        strcpy(pszNamePart, s_szVBoxHeadless_exe);
-
-        Utf8Str idStr = mData->mUuid.toString();
-        const char *apszArgs[] =
-        {
-            szPath,
-            "--comment", mUserData->s.strName.c_str(),
-            "--startvm", idStr.c_str(),
-            "--vrde", "config",
-            NULL, /* For "--capture". */
-            NULL, /* For "--sup-startup-log". */
-            NULL
-        };
-        unsigned iArg = 7;
-        if (!strFrontend.compare("capture", Utf8Str::CaseInsensitive))
-            apszArgs[iArg++] = "--capture";
-        apszArgs[iArg++] = pszSupHardeningLogArg;
-
-# ifdef RT_OS_WINDOWS
-        vrc = RTProcCreate(szPath, apszArgs, env, RTPROC_FLAGS_NO_WINDOW, &pid);
-# else
-        vrc = RTProcCreate(szPath, apszArgs, env, 0, &pid);
-# endif
-    }
-#else /* !VBOX_WITH_HEADLESS */
-    if (0)
-        ;
-#endif /* !VBOX_WITH_HEADLESS */
-    else
-    {
-        RTEnvDestroy(env);
-        return setError(E_INVALIDARG,
-                        tr("Invalid frontend name: '%s'"),
-                        strFrontend.c_str());
-    }
-
-    RTEnvDestroy(env);
-
-    if (RT_FAILURE(vrc))
-        return setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
-                            tr("Could not launch a process for the machine '%s' (%Rrc)"),
-                            mUserData->s.strName.c_str(), vrc);
-
-    LogFlowThisFunc(("launched.pid=%d(0x%x)\n", pid, pid));
+#endif /* VBOX_WITH_VBOXSDS && RT_OS_WINDOWS */
+    {
+        int vrc = MachineLaunchVMCommonWorker(idStr, strMachineName, strFrontend, strEnvironment, strSupHardeningLogArg,
+                                              strAppOverride, 0 /*fFlags*/, NULL /*pvExtraData*/, pid);
+        if (RT_FAILURE(vrc))
+            return setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
+                                tr("Could not launch the VM process for the machine '%s' (%Rrc)"), strMachineName.c_str(), vrc);
+    }
+
+    LogRel(("Launched VM: %u pid: %u (%#x) frontend: %s name: %s\n",
+            idStr.c_str(), pid, pid, strFrontend.c_str(), strMachineName.c_str()));
 
     if (!fSeparate)
Index: /trunk/src/VBox/Main/src-server/generic/AutostartDb-generic.cpp
===================================================================
--- /trunk/src/VBox/Main/src-server/generic/AutostartDb-generic.cpp	(revision 80568)
+++ /trunk/src/VBox/Main/src-server/generic/AutostartDb-generic.cpp	(revision 80569)
@@ -190,5 +190,5 @@
     rc = autostartModifyDb(true /* fAutostart */, true /* fAddVM */);
     RTCritSectLeave(&this->CritSect);
-#elif defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
+#elif defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_WINDOWS)
     NOREF(pszVMId); /* Not needed */
     rc = VINF_SUCCESS;
@@ -210,5 +210,5 @@
     rc = autostartModifyDb(true /* fAutostart */, false /* fAddVM */);
     RTCritSectLeave(&this->CritSect);
-#elif defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
+#elif defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_WINDOWS)
     NOREF(pszVMId); /* Not needed */
     rc = VINF_SUCCESS;
@@ -230,5 +230,5 @@
     rc = autostartModifyDb(false /* fAutostart */, true /* fAddVM */);
     RTCritSectLeave(&this->CritSect);
-#elif defined(RT_OS_DARWIN)
+#elif defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS)
     NOREF(pszVMId); /* Not needed */
     rc = VINF_SUCCESS;
@@ -250,13 +250,13 @@
     rc = autostartModifyDb(false /* fAutostart */, false /* fAddVM */);
     RTCritSectLeave(&this->CritSect);
-#elif defined(RT_OS_DARWIN)
-    NOREF(pszVMId); /* Not needed */
-    rc = VINF_SUCCESS;
-#else
-    NOREF(pszVMId);
-    rc = VERR_NOT_SUPPORTED;
-#endif
-
-    return rc;
-}
-
+#elif defined(RT_OS_DARWIN) || defined (RT_OS_WINDOWS)
+    NOREF(pszVMId); /* Not needed */
+    rc = VINF_SUCCESS;
+#else
+    NOREF(pszVMId);
+    rc = VERR_NOT_SUPPORTED;
+#endif
+
+    return rc;
+}
+
Index: /trunk/src/VBox/Runtime/common/fuzz/fuzz-observer.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/fuzz/fuzz-observer.cpp	(revision 80568)
+++ /trunk/src/VBox/Runtime/common/fuzz/fuzz-observer.cpp	(revision 80569)
@@ -474,5 +474,5 @@
 {
     int rc = RTProcCreateEx(pThis->pszBinary, &pExecCtx->apszArgs[0], pExecCtx->hEnv, 0 /*fFlags*/, &pExecCtx->StdinHandle,
-                            &pExecCtx->StdoutHandle, &pExecCtx->StderrHandle, NULL, NULL, &pExecCtx->hProc);
+                            &pExecCtx->StdoutHandle, &pExecCtx->StderrHandle, NULL, NULL, NULL, &pExecCtx->hProc);
     if (RT_SUCCESS(rc))
     {
@@ -577,5 +577,5 @@
 {
     int rc = RTProcCreateEx(pThis->pszBinary, &pExecCtx->apszArgs[0], pExecCtx->hEnv, 0 /*fFlags*/, &pExecCtx->StdinHandle,
-                            &pExecCtx->StdoutHandle, &pExecCtx->StderrHandle, NULL, NULL, &pExecCtx->hProc);
+                            &pExecCtx->StdoutHandle, &pExecCtx->StderrHandle, NULL, NULL, NULL, &pExecCtx->hProc);
     if (RT_SUCCESS(rc))
     {
Index: /trunk/src/VBox/Runtime/generic/RTProcDaemonize-generic.cpp
===================================================================
--- /trunk/src/VBox/Runtime/generic/RTProcDaemonize-generic.cpp	(revision 80568)
+++ /trunk/src/VBox/Runtime/generic/RTProcDaemonize-generic.cpp	(revision 80569)
@@ -84,5 +84,5 @@
                                 RTPROC_FLAGS_DETACHED | RTPROC_FLAGS_SAME_CONTRACT,
                                 &hStdIn, &hStdOutAndErr, &hStdOutAndErr,
-                                NULL /*pszAsUser*/,  NULL /*pszPassword*/, NULL /*phProcess*/);
+                                NULL /*pszAsUser*/,  NULL /*pszPassword*/, NULL /*pExtraData*/, NULL /*phProcess*/);
 
             RTFileClose(hStdOutAndErr.u.hFile);
Index: /trunk/src/VBox/Runtime/r3/posix/process-creation-posix.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/posix/process-creation-posix.cpp	(revision 80568)
+++ /trunk/src/VBox/Runtime/r3/posix/process-creation-posix.cpp	(revision 80569)
@@ -512,5 +512,5 @@
     return RTProcCreateEx(pszExec, papszArgs, Env, fFlags,
                           NULL, NULL, NULL,  /* standard handles */
-                          NULL /*pszAsUser*/, NULL /* pszPassword*/,
+                          NULL /*pszAsUser*/, NULL /* pszPassword*/, NULL /*pvExtraData*/,
                           pProcess);
 }
@@ -682,5 +682,5 @@
 RTR3DECL(int)   RTProcCreateEx(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags,
                                PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser,
-                               const char *pszPassword, PRTPROCESS phProcess)
+                               const char *pszPassword, void *pvExtraData, PRTPROCESS phProcess)
 {
     int rc;
@@ -704,4 +704,5 @@
         return VERR_PROC_DETACH_NOT_SUPPORTED;
 #endif
+    AssertReturn(pvExtraData == NULL || (fFlags & RTPROC_FLAGS_DESIRED_SESSION_ID), VERR_INVALID_PARAMETER);
 
     /*
Index: /trunk/src/VBox/Runtime/r3/win/process-win.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/win/process-win.cpp	(revision 80568)
+++ /trunk/src/VBox/Runtime/r3/win/process-win.cpp	(revision 80569)
@@ -140,8 +140,6 @@
 /* advapi32.dll: */
 static PFNCREATEPROCESSWITHLOGON        g_pfnCreateProcessWithLogonW    = NULL;
-static PFNLSALOOKUPNAMES2               g_pfnLsaLookupNames2            = NULL;
 static decltype(LogonUserW)            *g_pfnLogonUserW                 = NULL;
 static decltype(CreateProcessAsUserW)  *g_pfnCreateProcessAsUserW       = NULL;
-static decltype(LsaNtStatusToWinError) *g_pfnLsaNtStatusToWinError      = NULL;
 /* user32.dll: */
 static decltype(OpenWindowStationW)    *g_pfnOpenWindowStationW         = NULL;
@@ -353,7 +351,4 @@
         if (RT_FAILURE(rc)) { g_pfnCreateProcessWithLogonW = NULL; Assert(g_enmWinVer <= kRTWinOSType_NT4); }
 
-        rc = RTLdrGetSymbol(hMod, "LsaLookupNames2", (void **)&g_pfnLsaLookupNames2);
-        if (RT_FAILURE(rc)) { g_pfnLsaLookupNames2 = NULL; Assert(g_enmWinVer <= kRTWinOSType_NT4); }
-
         rc = RTLdrGetSymbol(hMod, "LogonUserW", (void **)&g_pfnLogonUserW);
         if (RT_FAILURE(rc)) { g_pfnLogonUserW = NULL; Assert(g_enmWinVer <= kRTWinOSType_NT350); }
@@ -361,7 +356,4 @@
         rc = RTLdrGetSymbol(hMod, "CreateProcessAsUserW", (void **)&g_pfnCreateProcessAsUserW);
         if (RT_FAILURE(rc)) { g_pfnCreateProcessAsUserW = NULL; Assert(g_enmWinVer <= kRTWinOSType_NT350); }
-
-        rc = RTLdrGetSymbol(hMod, "LsaNtStatusToWinError", (void **)&g_pfnLsaNtStatusToWinError);
-        if (RT_FAILURE(rc)) { g_pfnLsaNtStatusToWinError = NULL; Assert(g_enmWinVer <= kRTWinOSType_NT350); }
 
         RTLdrClose(hMod);
@@ -413,5 +405,5 @@
                           NULL, NULL, NULL,  /* standard handles */
                           NULL /*pszAsUser*/, NULL /* pszPassword*/,
-                          pProcess);
+                          NULL /*pvExtraData*/, pProcess);
 }
 
@@ -482,14 +474,17 @@
 
 /**
- * Get the process token of the process indicated by @a dwPID if the @a pSid
- * matches.
+ * Get the process token of the process indicated by @a dwPID if the @a pSid and
+ * @a idSessionDesired matches.
  *
  * @returns IPRT status code.
- * @param   dwPid           The process identifier.
- * @param   pSid            The secure identifier of the user.
- * @param   phToken         Where to return the a duplicate of the process token
- *                          handle on success. (The caller closes it.)
- */
-static int rtProcWinGetProcessTokenHandle(DWORD dwPid, PSID pSid, PHANDLE phToken)
+ * @param   dwPid               The process identifier.
+ * @param   pSid                The secure identifier of the user.
+ * @param   idDesiredSession    The session the process candidate should
+ *                              preferably belong to, UINT32_MAX if anything
+ *                              goes.
+ * @param   phToken             Where to return the a duplicate of the process token
+ *                              handle on success. (The caller closes it.)
+ */
+static int rtProcWinGetProcessTokenHandle(DWORD dwPid, PSID pSid, DWORD idDesiredSession, PHANDLE phToken)
 {
     AssertPtr(pSid);
@@ -502,8 +497,11 @@
         HANDLE hTokenProc;
         if (OpenProcessToken(hProc,
-                             TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE
+                             TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_IMPERSONATE
                              | TOKEN_ASSIGN_PRIMARY | TOKEN_ADJUST_SESSIONID | TOKEN_READ | TOKEN_WRITE,
                              &hTokenProc))
         {
+            /*
+             * Query the user SID from the token.
+             */
             SetLastError(NO_ERROR);
             DWORD   dwSize = 0;
@@ -519,13 +517,30 @@
                     if (GetTokenInformation(hTokenProc, TokenUser, pTokenUser, dwSize, &dwSize))
                     {
+                        /*
+                         * Match token user with the user we're want to create a process as.
+                         */
                         if (   IsValidSid(pTokenUser->User.Sid)
                             && EqualSid(pTokenUser->User.Sid, pSid))
                         {
                             /*
-                             * So we found the process instance which belongs to the user we want to
-                             * to run our new process under. This duplicated token will be used for
-                             * the actual CreateProcessAsUserW() call then.
+                             * Do we need to match the session ID?
                              */
-                            rc = rtProcWinDuplicateToken(hTokenProc, phToken);
+                            rc = VINF_SUCCESS;
+                            if (idDesiredSession != UINT32_MAX)
+                            {
+                                DWORD idCurSession = UINT32_MAX;
+                                if (GetTokenInformation(hTokenProc, TokenSessionId, &idCurSession, sizeof(DWORD), &dwSize))
+                                    rc = idDesiredSession == idCurSession ? VINF_SUCCESS : VERR_NOT_FOUND;
+                                else
+                                    rc = RTErrConvertFromWin32(GetLastError());
+                            }
+                            if (RT_SUCCESS(rc))
+                            {
+                                /*
+                                 * Got a match.  Duplicate the token.  This duplicated token will
+                                 * be used for the actual CreateProcessAsUserW() call then.
+                                 */
+                                rc = rtProcWinDuplicateToken(hTokenProc, phToken);
+                            }
                         }
                         else
@@ -627,5 +642,5 @@
                         if (   cbRet > 0
                             && _stricmp(pszProcName, papszNames[i]) == 0
-                            && RT_SUCCESS(rtProcWinGetProcessTokenHandle(paPids[iPid], pSid, phToken)))
+                            && RT_SUCCESS(rtProcWinGetProcessTokenHandle(paPids[iPid], pSid, UINT32_MAX, phToken)))
                             fFound = true;
                         CloseHandle(hProc);
@@ -645,14 +660,17 @@
 
 /**
- * Finds a one of the processes in @a papszNames running with user @a pSid and
- * returns a duplicate handle to its token.
+ * Finds a one of the processes in @a papszNames running with user @a pSid and possibly
+ * in the required windows session. Returns a duplicate handle to its token.
  *
  * @returns Success indicator.
- * @param   papszNames      The process candidates, in prioritized order.
- * @param   pSid            The secure identifier of the user.
- * @param   phToken         Where to return the token handle - duplicate,
- *                          caller closes it on success.
- */
-static bool rtProcWinFindTokenByProcess(const char * const *papszNames, PSID pSid, PHANDLE phToken)
+ * @param   papszNames          The process candidates, in prioritized order.
+ * @param   pSid                The secure identifier of the user.
+ * @param   idDesiredSession    The session the process candidate should
+ *                              belong to if possible, UINT32_MAX if anything
+ *                              goes.
+ * @param   phToken             Where to return the token handle - duplicate,
+ *                              caller closes it on success.
+ */
+static bool rtProcWinFindTokenByProcess(const char * const *papszNames, PSID pSid, uint32_t idDesiredSession, PHANDLE phToken)
 {
     AssertPtr(papszNames);
@@ -685,5 +703,5 @@
                         if (_stricmp(ProcEntry.szExeFile, papszNames[i]) == 0)
                         {
-                            int rc = rtProcWinGetProcessTokenHandle(ProcEntry.th32ProcessID, pSid, phToken);
+                            int rc = rtProcWinGetProcessTokenHandle(ProcEntry.th32ProcessID, pSid, idDesiredSession, phToken);
                             if (RT_SUCCESS(rc))
                             {
@@ -1022,4 +1040,5 @@
     Assert(pSidRet);
     RTMemTmpFree(pUser);
+    *prc = VINF_SUCCESS;
     return pSidRet;
 }
@@ -1562,5 +1581,5 @@
                                   RTENV hEnv, DWORD dwCreationFlags,
                                   STARTUPINFOW *pStartupInfo, PROCESS_INFORMATION *pProcInfo,
-                                  uint32_t fFlags, const char *pszExec)
+                                  uint32_t fFlags, const char *pszExec, uint32_t idDesiredSession)
 {
     /*
@@ -1614,163 +1633,9 @@
              * For the token search we need a SID.
              */
-            PSID pSid = NULL;
-            if ((fFlags & RTPROC_FLAGS_AS_IMPERSONATED_TOKEN) || pwszUser == NULL)
-                pSid = rtProcWinGetTokenUserSid(hTokenLogon, &rc);
-            else
-            {
-                /** @todo r=bird: why can't we do this in the same manner as in the
-                 *        RTPROC_FLAGS_AS_IMPERSONATED_TOKEN case above? */
-
-                /* Try query the SID and domain sizes first. */
-                DWORD        cbSid      = 0; /* Must be zero to query size! */
-                DWORD        cwcDomain  = 0;
-                SID_NAME_USE SidNameUse = SidTypeUser;
-                fRc = LookupAccountNameW(NULL, pwszUser, NULL, &cbSid, NULL, &cwcDomain, &SidNameUse);
-                if (!fRc)
-                {
-                    dwErr = GetLastError();
-
-                    /*
-                     * The errors ERROR_TRUSTED_DOMAIN_FAILURE and ERROR_TRUSTED_RELATIONSHIP_FAILURE
-                     * can happen if an ADC (Active Domain Controller) is offline or not reachable.
-                     *
-                     * Try to handle these errors gracefully by asking the local LSA cache of the
-                     * client OS instead then. For this to work, the desired user must have at
-                     * least logged in once at that client -- otherwise there will be no cached
-                     * authentication available and this fallback will fail.
-                     */
-                    if (   g_pfnLsaLookupNames2 /* >= Windows XP */
-                        && (   dwErr == ERROR_TRUSTED_DOMAIN_FAILURE
-                            || dwErr == ERROR_TRUSTED_RELATIONSHIP_FAILURE))
-                    {
-                        LSA_OBJECT_ATTRIBUTES objAttr;
-                        RT_ZERO(objAttr);
-                        objAttr.Length = sizeof(LSA_OBJECT_ATTRIBUTES);
-
-                        LSA_HANDLE lsahPolicy;
-                        NTSTATUS ntSts = LsaOpenPolicy(NULL, &objAttr, POLICY_LOOKUP_NAMES, &lsahPolicy);
-                        if (ntSts == STATUS_SUCCESS)
-                        {
-                            RTPROCWINACCOUNTINFO accountInfo;
-                            RT_ZERO(accountInfo);
-                            rc = rtProcWinParseAccountInfo(pwszUser, &accountInfo);
-                            AssertRC(rc);
-                            AssertPtr(accountInfo.pwszUserName);
-
-                            LSA_UNICODE_STRING lsaUser;
-                            lsaUser.Buffer        = accountInfo.pwszUserName;
-                            lsaUser.Length        = (USHORT)(RTUtf16Len(accountInfo.pwszUserName) * sizeof(WCHAR));
-                            lsaUser.MaximumLength = lsaUser.Length;
-
-                            PLSA_REFERENCED_DOMAIN_LIST pDomainList     = NULL;
-                            PLSA_TRANSLATED_SID2        pTranslatedSids = NULL;
-                            ntSts = g_pfnLsaLookupNames2(lsahPolicy, 0 /* Flags */,
-                                                         1 /* Number of users to lookup */,
-                                                         &lsaUser, &pDomainList, &pTranslatedSids);
-                            if (ntSts == STATUS_SUCCESS)
-                            {
-                                AssertPtr(pDomainList);
-                                AssertPtr(pTranslatedSids);
-# ifdef DEBUG
-                                LogRelFunc(("LsaLookupNames2: cDomains=%u, DomainIndex=%ld, SidUse=%ld\n",
-                                            pDomainList->Entries, pTranslatedSids[0].DomainIndex, pTranslatedSids[0].Use));
-# endif
-                                Assert(pTranslatedSids[0].Use == SidTypeUser);
-
-                                if (pDomainList->Entries)
-                                {
-                                    AssertPtr(pDomainList->Domains);
-                                    LogRelFunc(("LsaLookupNames2: Domain=%ls\n",
-                                                pDomainList->Domains[pTranslatedSids[0].DomainIndex].Name.Buffer));
-                                }
-
-                                cbSid = GetLengthSid(pTranslatedSids->Sid) + 16;
-                                Assert(cbSid);
-                                pSid = (PSID)RTMemAllocZ(cbSid);
-                                if (!CopySid(cbSid, pSid, pTranslatedSids->Sid))
-                                {
-                                    dwErr = GetLastError();
-                                    LogRelFunc(("CopySid failed with: %ld\n", dwErr));
-                                    rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_2;
-                                }
-                            }
-                            else if (g_pfnLsaNtStatusToWinError)
-                            {
-                                dwErr = g_pfnLsaNtStatusToWinError(ntSts);
-                                LogRelFunc(("LsaLookupNames2 failed with: %ld\n", dwErr));
-                                rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_2;
-                            }
-                            else
-                            {
-                                LogRelFunc(("LsaLookupNames2 failed with: %#x\n", ntSts));
-                                rc = RTErrConvertFromNtStatus(ntSts);
-                            }
-
-                            if (pDomainList)
-                            {
-                                LsaFreeMemory(pDomainList);
-                                pDomainList = NULL;
-                            }
-                            if (pTranslatedSids)
-                            {
-                                LsaFreeMemory(pTranslatedSids);
-                                pTranslatedSids = NULL;
-                            }
-
-                            rtProcWinFreeAccountInfo(&accountInfo);
-                            LsaClose(lsahPolicy);
-                        }
-                        else if (g_pfnLsaNtStatusToWinError)
-                        {
-                            dwErr = g_pfnLsaNtStatusToWinError(ntSts);
-                            LogRelFunc(("LsaOpenPolicy failed with: %ld\n", dwErr));
-                            rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_3;
-                        }
-                        else
-                        {
-                            LogRelFunc(("LsaOpenPolicy failed with: %#x\n", ntSts));
-                            rc = RTErrConvertFromNtStatus(ntSts);
-                        }
-
-                        /* Note: pSid will be free'd down below. */
-                    }
-                    else if (dwErr == ERROR_INSUFFICIENT_BUFFER)
-                    {
-                        /* Allocate memory for the LookupAccountNameW output buffers and do it for real. */
-                        cbSid = fRc && cbSid != 0 ? cbSid + 16 : _1K;
-                        pSid = (PSID)RTMemAllocZ(cbSid);
-                        if (pSid)
-                        {
-                            cwcDomain = fRc ? cwcDomain + 2 : _4K;
-                            PRTUTF16 pwszDomain = (PRTUTF16)RTMemAllocZ(cwcDomain * sizeof(RTUTF16));
-                            if (pwszDomain)
-                            {
-                                /* Note: Just pass in the UPN (User Principal Name), e.g. someone@example.com */
-                                if (!LookupAccountNameW(NULL /*lpSystemName*/, pwszUser, pSid, &cbSid, pwszDomain, &cwcDomain,
-                                                        &SidNameUse))
-                                {
-                                    dwErr = GetLastError();
-                                    LogRelFunc(("LookupAccountNameW(2) failed with: %ld\n", dwErr));
-                                    rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_4;
-                                }
-
-                                RTMemFree(pwszDomain);
-                            }
-                            else
-                                rc = VERR_NO_MEMORY;
-
-                            /* Note: pSid will be free'd down below. */
-                        }
-                        else
-                            rc = VERR_NO_MEMORY;
-                    }
-                    else
-                    {
-                        LogRelFunc(("LookupAccountNameW(1) failed with: %ld\n", dwErr));
-                        rc = dwErr != NO_ERROR ? RTErrConvertFromWin32(dwErr) : VERR_INTERNAL_ERROR_2;
-                    }
-                }
-            }
-
+            PSID pSid = rtProcWinGetTokenUserSid(hTokenLogon, &rc);
+
+            /*
+             * If we got a valid SID, search the running processes.
+             */
             /*
              * If we got a valid SID, search the running processes.
@@ -1792,5 +1657,5 @@
                         NULL
                     };
-                    fFound = rtProcWinFindTokenByProcess(s_papszProcNames, pSid, &hTokenUserDesktop);
+                    fFound = rtProcWinFindTokenByProcess(s_papszProcNames, pSid, idDesiredSession, &hTokenUserDesktop);
                     dwErr  = 0;
                 }
@@ -1838,11 +1703,14 @@
             {
                 /*
-                 * Load the profile, if requested.  (Must be done prior to
-                 * creating the enviornment.)
+                 * Load the profile, if requested.  (Must be done prior to creating the enviornment.)
+                 *
+                 * Note! We don't have sufficient rights when impersonating a user, but we can
+                 *       ASSUME the user is logged on and has its profile loaded into HKEY_USERS already.
                  */
                 PROFILEINFOW ProfileInfo;
                 PRTUTF16     pwszUserFree = NULL;
                 RT_ZERO(ProfileInfo);
-                if (fFlags & RTPROC_FLAGS_PROFILE) /** @todo r=bird: We probably don't need to load anything if pwszUser is NULL... */
+                /** @todo r=bird: We probably don't need to load anything if pwszUser is NULL... */
+                if ((fFlags & (RTPROC_FLAGS_PROFILE | RTPROC_FLAGS_AS_IMPERSONATED_TOKEN)) == RTPROC_FLAGS_PROFILE)
                 {
                     if (!pwszUser)
@@ -1882,15 +1750,4 @@
                                     rtProcWinStationPrep(hTokenToUse, pStartupInfo, &hOldWinStation);
 
-                                /* Specify a window station and desktop when start interactive
-                                 * process from service with an impersonated token. */
-                                /** @todo r=bird: Why is this needed? */
-                                /** @todo r=bird: Why don't we do this for the non-impersonated token case? */
-                                /** @todo r=bird: Remind me, does pure RDP logins get a winSta0 too, or do
-                                 *        the get a mangled name similar to the services? */
-                                if (   fFound
-                                    &&    (fFlags & (RTPROC_FLAGS_SERVICE | RTPROC_FLAGS_AS_IMPERSONATED_TOKEN))
-                                       ==           (RTPROC_FLAGS_SERVICE | RTPROC_FLAGS_AS_IMPERSONATED_TOKEN))
-                                    pStartupInfo->lpDesktop = L"WinSta0\\default";
-
                                 /*
                                  * Useful KB articles:
@@ -2199,5 +2056,5 @@
                                  RTENV hEnv, DWORD dwCreationFlags,
                                  STARTUPINFOW *pStartupInfo, PROCESS_INFORMATION *pProcInfo,
-                                 uint32_t fFlags, const char *pszExec)
+                                 uint32_t fFlags, const char *pszExec, uint32_t idDesiredSession)
 {
     /*
@@ -2216,5 +2073,5 @@
     }
     return rtProcWinCreateAsUser2(pwszUser, pwszPassword, ppwszExec, pwszCmdLine,
-                                  hEnv, dwCreationFlags, pStartupInfo, pProcInfo, fFlags, pszExec);
+                                  hEnv, dwCreationFlags, pStartupInfo, pProcInfo, fFlags, pszExec, idDesiredSession);
 }
 
@@ -2366,5 +2223,5 @@
 RTR3DECL(int)   RTProcCreateEx(const char *pszExec, const char * const *papszArgs, RTENV hEnv, uint32_t fFlags,
                                PCRTHANDLE phStdIn, PCRTHANDLE phStdOut, PCRTHANDLE phStdErr, const char *pszAsUser,
-                               const char *pszPassword, PRTPROCESS phProcess)
+                               const char *pszPassword, void *pvExtraData, PRTPROCESS phProcess)
 {
     /*
@@ -2381,4 +2238,15 @@
     AssertReturn(!pszPassword || pszAsUser, VERR_INVALID_PARAMETER);
     AssertPtrNullReturn(pszPassword, VERR_INVALID_POINTER);
+
+    /* Extra data: */
+    uint32_t idDesiredSession = UINT32_MAX;
+    if (   (fFlags & (RTPROC_FLAGS_DESIRED_SESSION_ID | RTPROC_FLAGS_SERVICE))
+        ==           (RTPROC_FLAGS_DESIRED_SESSION_ID | RTPROC_FLAGS_SERVICE))
+    {
+        AssertPtrReturn(pvExtraData, VERR_INVALID_POINTER);
+        idDesiredSession = *(uint32_t *)pvExtraData;
+    }
+    else
+        AssertReturn(!(fFlags & RTPROC_FLAGS_DESIRED_SESSION_ID), VERR_INVALID_FLAGS);
 
     /*
@@ -2585,5 +2453,5 @@
                         rc = rtProcWinCreateAsUser(pwszUser, pwszPassword,
                                                    &pwszExec, pwszCmdLine, hEnv, dwCreationFlags,
-                                                   &StartupInfo, &ProcInfo, fFlags, pszExec);
+                                                   &StartupInfo, &ProcInfo, fFlags, pszExec, idDesiredSession);
 
                         if (pwszPassword && *pwszPassword)
Index: /trunk/src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp	(revision 80568)
+++ /trunk/src/VBox/Runtime/testcase/tstRTProcCreateEx.cpp	(revision 80569)
@@ -219,5 +219,5 @@
     RTPROCESS hProc;
     RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/,
-                                         NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
+                                         NULL, NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
     RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
     RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
@@ -233,5 +233,5 @@
     int rc;
     RTTESTI_CHECK_RC(rc = RTProcCreateEx(g_szExecName, apszArgs, hEnvChange, RTPROC_FLAGS_ENV_CHANGE_RECORD,
-                                         NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
+                                         NULL, NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
     if (RT_SUCCESS(rc))
     {
@@ -248,5 +248,5 @@
     apszArgs[2] = "noinherit";
     RTTESTI_CHECK_RC(rc = RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, RTPROC_FLAGS_PROFILE,
-                                         NULL, NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
+                                         NULL, NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
     if (RT_SUCCESS(rc))
     {
@@ -263,5 +263,5 @@
     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);
+                                         NULL, NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
     if (RT_SUCCESS(rc))
     {
@@ -386,5 +386,5 @@
     RTPROCESS hProc;
     int rc = RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL, NULL, NULL,
-                            "non-existing-user", "wrong-password", &hProc);
+                            "non-existing-user", "wrong-password", NULL, &hProc);
     if (rc != VERR_AUTHENTICATION_FAILURE && rc != VERR_PRIVILEGE_NOT_HELD && rc != VERR_PROC_TCB_PRIV_NOT_HELD)
         RTTestIFailed("rc=%Rrc", rc);
@@ -392,9 +392,9 @@
     /* Test for invalid application. */
     RTTESTI_CHECK_RC(RTProcCreateEx("non-existing-app", apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
-                                    NULL, NULL, NULL, NULL, &hProc), VERR_FILE_NOT_FOUND);
+                                    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,
-                                         NULL, NULL, pszUser, pszPassword, &hProc), VINF_SUCCESS);
+                                         NULL, NULL, pszUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
     RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
     RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
@@ -431,5 +431,5 @@
     RTPROCESS hProc;
     RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, g_apszArgs4, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
-                                         NULL, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
+                                         NULL, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
     RTPROCSTATUS ProcStatus = { -1, RTPROCEXITREASON_ABEND };
     RTTESTI_CHECK_RC(RTProcWait(hProc, RTPROCWAIT_FLAGS_BLOCK, &ProcStatus), VINF_SUCCESS);
@@ -472,5 +472,5 @@
     RTPROCESS hProc;
     RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
-                                         &Handle, &Handle, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
+                                         &Handle, &Handle, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
     RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
 
@@ -537,5 +537,5 @@
     RTPROCESS hProc;
     RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
-                                         NULL, &Handle, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
+                                         NULL, &Handle, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
     RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
 
@@ -603,5 +603,5 @@
     RTPROCESS hProc;
     RTTESTI_CHECK_RC_RETV(RTProcCreateEx(g_szExecName, apszArgs, RTENV_DEFAULT, 0 /*fFlags*/, NULL,
-                                         &Handle, NULL, pszAsUser, pszPassword, &hProc), VINF_SUCCESS);
+                                         &Handle, NULL, pszAsUser, pszPassword, NULL, &hProc), VINF_SUCCESS);
     RTTESTI_CHECK_RC(RTPipeClose(hPipeW), VINF_SUCCESS);
 
Index: /trunk/src/VBox/ValidationKit/utils/TestExecServ/TestExecService.cpp
===================================================================
--- /trunk/src/VBox/ValidationKit/utils/TestExecServ/TestExecService.cpp	(revision 80568)
+++ /trunk/src/VBox/ValidationKit/utils/TestExecServ/TestExecService.cpp	(revision 80569)
@@ -2718,5 +2718,5 @@
         rc = RTProcCreateEx(pszExecName, papszArgs, pTxsExec->hEnv, 0 /*fFlags*/,
                             pTxsExec->StdIn.phChild, pTxsExec->StdOut.phChild, pTxsExec->StdErr.phChild,
-                            *pszUsername ? pszUsername : NULL, NULL,
+                            *pszUsername ? pszUsername : NULL, NULL, NULL,
                             &pTxsExec->hProcess);
         if (RT_SUCCESS(rc))
Index: /trunk/src/bldprogs/scmsubversion.cpp
===================================================================
--- /trunk/src/bldprogs/scmsubversion.cpp	(revision 80568)
+++ /trunk/src/bldprogs/scmsubversion.cpp	(revision 80569)
@@ -419,4 +419,5 @@
                                 NULL /*pszAsUser*/,
                                 NULL /*pszPassword*/,
+                                NULL /*pvExtraData*/,
                                 &hProc);
             rc2 = RTHandleClose(&hChildStdErr); AssertRC(rc2);
@@ -556,4 +557,5 @@
                             NULL /*pszAsUser*/,
                             NULL /*pszPassword*/,
+                            NULL /*pvExtraData*/,
                             &hProc);
 
Index: /trunk/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxproces.c
===================================================================
--- /trunk/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxproces.c	(revision 80568)
+++ /trunk/src/libs/xpcom18a4/nsprpub/pr/src/md/unix/uxproces.c	(revision 80569)
@@ -601,5 +601,5 @@
     vrc = RTProcCreateEx(path, (const char **)argv, childEnv,
                          RTPROC_FLAGS_DETACHED, pStdIn, pStdOut, pStdErr,
-                         NULL /* pszAsUser */, NULL /* pszPassword */,
+                         NULL /* pszAsUser */, NULL /* pszPassword */, NULL /* pExtraData */,
                          NULL /* phProcess */);
     if (newEnv != RTENV_DEFAULT) {
