VirtualBox

Changeset 80569 in vbox for trunk/src/VBox/Main


Ignore:
Timestamp:
Sep 3, 2019 2:34:21 PM (6 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
133086
Message:

Main: bugref:9341: Added VM autostart during boot support for windows host

Location:
trunk/src/VBox/Main
Files:
2 added
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/Makefile.kmk

    r80398 r80569  
    385385VBoxSDS_TEMPLATE = VBOXMAINEXE
    386386VBoxSDS_DEFS += VBOX_COM_OUTOFPROC_MODULE _WIN32_WINNT=0x0600
     387 ifdef VBOX_WITH_VBOXSDL
     388VBoxSDS_DEFS += VBOX_WITH_VBOXSDL
     389 endif
     390 ifdef VBOX_WITH_HEADLESS
     391VBoxSDS_DEFS += VBOX_WITH_HEADLESS
     392 endif
     393 ifdef VBOX_WITH_QTGUI
     394VBoxSDS_DEFS += VBOX_WITH_QTGUI
     395 endif
    387396VBoxSDS_INCS  = \
    388397        include \
     
    394403        src-global/win/VBoxSDS.cpp \
    395404        src-global/win/VirtualBoxSDSImpl.cpp \
    396         src-global/win/VBoxSDS.rc
     405        src-global/win/VBoxSDS.rc \
     406        src-all/MachineLaunchVMCommonWorker.cpp
    397407$(call KB_FN_DO_PASS0_ON_TARGET,VBoxSDS) # Sets VBoxSDS_0_OUTDIR
    398408
     
    553563        src-server/HostVideoInputDeviceImpl.cpp \
    554564        src-server/MachineImpl.cpp \
     565        src-all/MachineLaunchVMCommonWorker.cpp \
    555566        src-server/MachineImplCloneVM.cpp \
    556567        src-server/MachineImplMoveVM.cpp \
  • trunk/src/VBox/Main/idl/VirtualBox.xidl

    r80426 r80569  
    2703327033  <interface
    2703427034    name="IVirtualBoxSDS" extends="$unknown" notdual="yes"
    27035     uuid="152265b8-fe7d-4077-9dd6-032bc3f1c5a3"
     27035    uuid="bc1a2773-18f2-4066-08ce-1e44d59d84af"
    2703627036    wsmap="suppress" internal="yes"
    2703727037    reservedMethods="0" reservedAttributes="0"
     
    2706827068        <param name="pid" type="long" dir="in">
    2706927069          <desc>The process ID of the VBoxSVC instance (same as during registration).</desc>
     27070        </param>
     27071      </method>
     27072
     27073      <method name="launchVMProcess">
     27074        <desc>
     27075          Spawns a new process that will execute the virtual machine in the interactive
     27076          windows session of calling user. Any additional checks are performed by created
     27077          process itself
     27078
     27079          If launching the VM succeeds, the new VM process will create its own session
     27080          and write-lock the machine for it, preventing conflicting changes from other
     27081          processes. If the machine is already locked (because it is already running or
     27082          because another session has a write lock), launching the VM process will therefore
     27083          fail. Reversely, future attempts to obtain a write lock will also fail while the
     27084          machine is running.
     27085
     27086          Launching a VM process can take some time (a new VM is started in a new process,
     27087          for which memory and other resources need to be set up) but the method does
     27088          not wait for completion and just returns the PID of created process.
     27089
     27090          <result name="E_INVALIDARG">
     27091            Some of the parameters are invalid.
     27092          </result>
     27093          <result name="VBOX_E_IPRT_ERROR">
     27094            Launching process for machine failed.
     27095          </result>
     27096        </desc>
     27097        <param name="machine" type="wstring" dir="in">
     27098          <desc>
     27099            The name or id of the machine the VM will start for.
     27100          </desc>
     27101        </param>
     27102        <param name="comment" type="wstring" dir="in">
     27103          <desc>
     27104            The comment for VM.
     27105          </desc>
     27106        </param>
     27107        <param name="frontend" type="wstring" dir="in">
     27108          <desc>
     27109            Front-end to use for the new VM process. The following are currently supported:
     27110            <ul>
     27111              <li><tt>"gui"</tt>: VirtualBox Qt GUI front-end</li>
     27112              <li><tt>"headless"</tt>: VBoxHeadless (VRDE Server) front-end</li>
     27113              <li><tt>"sdl"</tt>: VirtualBox SDL front-end</li>
     27114              <li><tt>""</tt>: use the per-VM default frontend if set, otherwise
     27115                the global default defined in the system properties. If neither
     27116                are set, the API will launch a <tt>"gui"</tt> session, which may
     27117                fail if there is no windowing environment available. See
     27118                <link to="IMachine::defaultFrontend"/> and
     27119                <link to="ISystemProperties::defaultFrontend"/>.</li>
     27120            </ul>
     27121          </desc>
     27122        </param>
     27123        <param name="environmentChanges" type="wstring" dir="in">
     27124          <desc>
     27125            Environment changes to pass to the VM process, putenv style using newline as separator.
     27126            <!-- TODO: make this a safearray so values can safely contain newlines and '\'. -->
     27127          </desc>
     27128        </param>
     27129        <param name="cmdOptions" type="wstring" dir="in">
     27130          <desc>
     27131            Additional command line options to pass to the VM process.
     27132          </desc>
     27133        </param>
     27134        <param name="sessionId" type="unsigned long" dir="in">
     27135          <desc>
     27136            Windows session where the VM process should be launched.
     27137          </desc>
     27138        </param>
     27139        <param name="pid" type="unsigned long" dir="return">
     27140          <desc>The PID of created process.</desc>
    2707027141        </param>
    2707127142      </method>
  • trunk/src/VBox/Main/include/VirtualBoxSDSImpl.h

    r76562 r80569  
    9494    STDMETHOD(RegisterVBoxSVC)(IVBoxSVCRegistration *aVBoxSVC, LONG aPid, IUnknown **aExistingVirtualBox);
    9595    STDMETHOD(DeregisterVBoxSVC)(IVBoxSVCRegistration *aVBoxSVC, LONG aPid);
     96    STDMETHOD(LaunchVMProcess)(IN_BSTR aMachine, IN_BSTR aComment, IN_BSTR aFrontend, IN_BSTR aEnvironmentChanges,
     97                               IN_BSTR aCmdOptions, ULONG aSessionId, ULONG *aPid);
    9698    /** @} */
    9799
  • trunk/src/VBox/Main/src-all/ExtPackManagerImpl.cpp

    r77624 r80569  
    25082508                         NULL /*pszAsUser*/,
    25092509                         NULL /*pszPassword*/,
     2510                         NULL /*pvExtraData*/,
    25102511                         &hProcess);
    25112512    if (RT_SUCCESS(vrc))
  • trunk/src/VBox/Main/src-client/ClientTokenHolder.cpp

    r77436 r80569  
    250250    HANDLE initDoneSem = (HANDLE)data[1];
    251251
    252     HANDLE mutex = ::OpenMutex(MUTEX_ALL_ACCESS, FALSE, Bstr(strSessionId).raw());
    253     AssertMsg(mutex, ("cannot open token, err=%d\n", ::GetLastError()));
    254 
     252    Bstr bstrSessionId(strSessionId);
     253    HANDLE mutex = ::OpenMutex(MUTEX_ALL_ACCESS, FALSE, bstrSessionId.raw());
     254
     255    //AssertMsg(mutex, ("cannot open token, err=%u\n", ::GetLastError()));
     256    AssertMsg(mutex, ("cannot open token %ls, err=%u\n", bstrSessionId.raw(), ::GetLastError()));
    255257    if (mutex)
    256258    {
  • trunk/src/VBox/Main/src-global/win/VirtualBoxSDSImpl.cpp

    r76592 r80569  
    3131#include <iprt/critsect.h>
    3232#include <iprt/mem.h>
     33#include <iprt/process.h>
    3334#include <iprt/system.h>
    3435
     
    3738#include <sddl.h>
    3839#include <lmcons.h> /* UNLEN */
     40
     41#include "MachineLaunchVMCommonWorker.h"
     42
     43
     44/*********************************************************************************************************************************
     45*   Defined Constants And Macros                                                                                                 *
     46*********************************************************************************************************************************/
     47#define INTERACTIVE_SID_FLAG 0x1
     48#define LOCAL_SID_FLAG       0x2
     49#define LOGON_SID_FLAG       0x4
     50#define IS_INTERACTIVE       (LOCAL_SID_FLAG|INTERACTIVE_SID_FLAG|LOGON_SID_FLAG)
    3951
    4052
     
    388400        hrc = E_INVALIDARG;
    389401    LogRel2(("VirtualBoxSDS::deregisterVBoxSVC: returns %Rhrc\n", hrc));
     402    return hrc;
     403}
     404
     405
     406STDMETHODIMP VirtualBoxSDS::LaunchVMProcess(IN_BSTR aMachine, IN_BSTR aComment, IN_BSTR aFrontend, IN_BSTR aEnvironmentChanges,
     407                                            IN_BSTR aCmdOptions, ULONG aSessionId, ULONG *aPid)
     408{
     409    /*
     410     * Convert parameters to UTF-8.
     411     */
     412    Utf8Str strMachine(aMachine);
     413    Utf8Str strComment(aComment);
     414    Utf8Str strFrontend(aFrontend);
     415    Utf8Str strEnvironmentChanges(aEnvironmentChanges);
     416    Utf8Str strCmdOptions(aCmdOptions);
     417
     418    /*
     419     * Impersonate the caller.
     420     */
     421    HRESULT hrc = CoImpersonateClient();
     422    if (SUCCEEDED(hrc))
     423    {
     424        try
     425        {
     426            /*
     427             * Try launch the VM process as the client.
     428             */
     429            RTPROCESS pid;
     430            AssertCompile(sizeof(aSessionId) == sizeof(uint32_t));
     431            int vrc = ::MachineLaunchVMCommonWorker(strMachine, strComment, strFrontend, strEnvironmentChanges,
     432                                                    strCmdOptions, Utf8Str(),
     433                                                    RTPROC_FLAGS_AS_IMPERSONATED_TOKEN | RTPROC_FLAGS_SERVICE
     434                                                    | RTPROC_FLAGS_PROFILE | RTPROC_FLAGS_DESIRED_SESSION_ID,
     435                                                    &aSessionId, pid);
     436            if (RT_SUCCESS(vrc))
     437            {
     438                *aPid = (ULONG)pid;
     439                LogRel(("VirtualBoxSDS::LaunchVMProcess: launchVM succeeded\n"));
     440            }
     441            else if (vrc == VERR_INVALID_PARAMETER)
     442            {
     443                hrc = E_INVALIDARG;
     444                LogRel(("VirtualBoxSDS::LaunchVMProcess: launchVM failed: %Rhrc\n", hrc));
     445            }
     446            else
     447            {
     448                hrc = VBOX_E_IPRT_ERROR;
     449                LogRel(("VirtualBoxSDS::LaunchVMProcess: launchVM failed: %Rhrc (%Rrc)\n", hrc));
     450            }
     451        }
     452        catch (...)
     453        {
     454            hrc = E_UNEXPECTED;
     455        }
     456        CoRevertToSelf();
     457    }
     458    else
     459        LogRel(("VirtualBoxSDS::LaunchVMProcess: CoImpersonateClient failed: %Rhrc\n", hrc));
    390460    return hrc;
    391461}
     
    592662}
    593663
     664
    594665#ifdef WITH_WATCHER
    595666/**
  • trunk/src/VBox/Main/src-helper-apps/VBoxExtPackHelperApp.cpp

    r77178 r80569  
    15481548         */
    15491549        RTPROCESS hProcess;
    1550         rc = RTProcCreateEx(papszArgs[iSuArg], &papszArgs[iSuArg], RTENV_DEFAULT, 0 /*fFlags*/,
    1551                             NULL /*phStdIn*/, NULL /*phStdOut*/, NULL /*phStdErr*/, NULL /*pszAsUser*/, NULL /*pszPassword*/,
     1550        rc = RTProcCreateEx(papszArgs[iSuArg], &papszArgs[iSuArg], RTENV_DEFAULT, 0 /*fFlags*/, NULL /*phStdIn*/,
     1551                            NULL /*phStdOut*/, NULL /*phStdErr*/, NULL /*pszAsUser*/, NULL /*pszPassword*/, NULL /* pvExtraData*/,
    15521552                            &hProcess);
    15531553        if (RT_SUCCESS(rc))
  • trunk/src/VBox/Main/src-server/ClientToken.cpp

    r76553 r80569  
    4040#include "ClientToken.h"
    4141#include "MachineImpl.h"
     42
     43#ifdef RT_OS_WINDOWS
     44# include <sddl.h>
     45#endif
    4246
    4347Machine::ClientToken::ClientToken()
     
    8387#if defined(RT_OS_WINDOWS)
    8488    NOREF(pSessionMachine);
    85     Bstr tokenId = pMachine->mData->m_strConfigFileFull;
    86     for (size_t i = 0; i < tokenId.length(); i++)
    87         if (tokenId.raw()[i] == '\\')
    88             tokenId.raw()[i] = '/';
    89     mClientToken = ::CreateMutex(NULL, FALSE, tokenId.raw());
     89
     90    /* Get user's SID to use it as part of the mutex name to distinguish shared machine instances
     91     * between users
     92     */
     93    Utf8Str strUserSid;
     94    HANDLE  hProcessToken = INVALID_HANDLE_VALUE;
     95    if (::OpenProcessToken(::GetCurrentProcess(), TOKEN_QUERY, &hProcessToken))
     96    {
     97        DWORD dwSize = 0;
     98        BOOL fRc = ::GetTokenInformation(hProcessToken, TokenUser, NULL, 0, &dwSize);
     99        DWORD dwErr = ::GetLastError();
     100        if (!fRc && dwErr == ERROR_INSUFFICIENT_BUFFER && dwSize > 0)
     101        {
     102            PTOKEN_USER pTokenUser = (PTOKEN_USER)RTMemTmpAllocZ(dwSize);
     103            if (pTokenUser)
     104            {
     105                if (::GetTokenInformation(hProcessToken, TokenUser, pTokenUser, dwSize, &dwSize))
     106                {
     107                    PRTUTF16 wstrSid = NULL;
     108                    if (::ConvertSidToStringSid(pTokenUser->User.Sid, &wstrSid))
     109                    {
     110                        strUserSid = wstrSid;
     111                        ::LocalFree(wstrSid);
     112                    }
     113                    else
     114                        AssertMsgFailed(("Cannot convert SID to string, err=%u", ::GetLastError()));
     115                }
     116                else
     117                    AssertMsgFailed(("Cannot get thread access token information, err=%u", ::GetLastError()));
     118                RTMemFree(pTokenUser);
     119            }
     120            else
     121                AssertMsgFailed(("No memory"));
     122        }
     123        else
     124            AssertMsgFailed(("Cannot get thread access token information, err=%u", ::GetLastError()));
     125        CloseHandle(hProcessToken);
     126    }
     127    else
     128        AssertMsgFailed(("Cannot get thread access token, err=%u", ::GetLastError()));
     129
     130    Bstr tokenId = Bstr(Utf8Str("Global\\") + strUserSid + "/" + pMachine->mData->mUuid.toString());
     131
     132    /* create security descriptor to allow SYNCHRONIZE access from any windows sessions and users.
     133     * otherwise VM can't open the mutex if VBoxSVC and VM are in different session (e.g. some VM
     134     * started by autostart service)
     135     *
     136     * SDDL string contains following ACEs:
     137     *   CreateOwner           : MUTEX_ALL_ACCESS
     138     *   System                : MUTEX_ALL_ACCESS
     139     *   BuiltInAdministrators : MUTEX_ALL_ACCESS
     140     *   Everyone              : SYNCHRONIZE|MUTEX_MODIFY_STATE
     141     */
     142
     143    //static const RTUTF16 s_wszSecDesc[] = L"D:(A;;0x1F0001;;;CO)(A;;0x1F0001;;;SY)(A;;0x1F0001;;;BA)(A;;0x100001;;;WD)";
     144    com::BstrFmt bstrSecDesc("O:%sD:(A;;0x1F0001;;;CO)(A;;0x1F0001;;;SY)(A;;0x1F0001;;;BA)", strUserSid.c_str());
     145    PSECURITY_DESCRIPTOR pSecDesc = NULL;
     146    //AssertMsgStmt(::ConvertStringSecurityDescriptorToSecurityDescriptor(s_wszSecDesc, SDDL_REVISION_1, &pSecDesc, NULL),
     147    AssertMsgStmt(::ConvertStringSecurityDescriptorToSecurityDescriptor(bstrSecDesc.raw(), SDDL_REVISION_1, &pSecDesc, NULL),
     148                  ("Cannot create security descriptor for token '%ls', err=%u", tokenId.raw(), GetLastError()),
     149                  pSecDesc = NULL);
     150
     151    SECURITY_ATTRIBUTES SecAttr;
     152    SecAttr.lpSecurityDescriptor = pSecDesc;
     153    SecAttr.nLength              = sizeof(SecAttr);
     154    SecAttr.bInheritHandle       = FALSE;
     155    mClientToken = ::CreateMutex(&SecAttr, FALSE, tokenId.raw());
    90156    mClientTokenId = tokenId;
    91     AssertMsg(mClientToken,
    92               ("Cannot create token '%s', err=%d",
    93                mClientTokenId.c_str(), ::GetLastError()));
     157    AssertMsg(mClientToken, ("Cannot create token '%s', err=%d", mClientTokenId.c_str(), ::GetLastError()));
     158
     159    if (pSecDesc)
     160        ::LocalFree(pSecDesc);
     161
    94162#elif defined(RT_OS_OS2)
    95163    NOREF(pSessionMachine);
  • trunk/src/VBox/Main/src-server/MachineImpl.cpp

    r80074 r80569  
    4949#include "MachineImplMoveVM.h"
    5050#include "ExtPackManagerImpl.h"
     51#include "MachineLaunchVMCommonWorker.h"
    5152
    5253// generated header
     
    74097410    }
    74107411
    7411     /* get the path to the executable */
    7412     char szPath[RTPATH_MAX];
    7413     RTPathAppPrivateArch(szPath, sizeof(szPath) - 1);
    7414     size_t cchBufLeft = strlen(szPath);
    7415     szPath[cchBufLeft++] = RTPATH_DELIMITER;
    7416     szPath[cchBufLeft] = 0;
    7417     char *pszNamePart = szPath + cchBufLeft;
    7418     cchBufLeft = sizeof(szPath) - cchBufLeft;
    7419 
    7420     int vrc = VINF_SUCCESS;
    7421     RTPROCESS pid = NIL_RTPROCESS;
    7422 
    7423     RTENV env = RTENV_DEFAULT;
    7424 
    7425     if (!strEnvironment.isEmpty())
    7426     {
    7427         char *newEnvStr = NULL;
    7428 
    7429         do
    7430         {
    7431             /* clone the current environment */
    7432             int vrc2 = RTEnvClone(&env, RTENV_DEFAULT);
    7433             AssertRCBreakStmt(vrc2, vrc = vrc2);
    7434 
    7435             newEnvStr = RTStrDup(strEnvironment.c_str());
    7436             AssertPtrBreakStmt(newEnvStr, vrc = vrc2);
    7437 
    7438             /* put new variables to the environment
    7439              * (ignore empty variable names here since RTEnv API
    7440              * intentionally doesn't do that) */
    7441             char *var = newEnvStr;
    7442             for (char *p = newEnvStr; *p; ++p)
    7443             {
    7444                 if (*p == '\n' && (p == newEnvStr || *(p - 1) != '\\'))
    7445                 {
    7446                     *p = '\0';
    7447                     if (*var)
    7448                     {
    7449                         char *val = strchr(var, '=');
    7450                         if (val)
    7451                         {
    7452                             *val++ = '\0';
    7453                             vrc2 = RTEnvSetEx(env, var, val);
    7454                         }
    7455                         else
    7456                             vrc2 = RTEnvUnsetEx(env, var);
    7457                         if (RT_FAILURE(vrc2))
    7458                             break;
    7459                     }
    7460                     var = p + 1;
    7461                 }
    7462             }
    7463             if (RT_SUCCESS(vrc2) && *var)
    7464                 vrc2 = RTEnvPutEx(env, var);
    7465 
    7466             AssertRCBreakStmt(vrc2, vrc = vrc2);
    7467         }
    7468         while (0);
    7469 
    7470         if (newEnvStr != NULL)
    7471             RTStrFree(newEnvStr);
    7472     }
    7473 
    74747412    /* Hardening logging */
    74757413#if defined(RT_OS_WINDOWS) && defined(VBOX_WITH_HARDENING)
     
    74937431        RTFileDelete(strOldStartupLogFile.c_str());
    74947432    }
    7495     const char *pszSupHardeningLogArg = strSupHardeningLogArg.c_str();
    74967433#else
    7497     const char *pszSupHardeningLogArg = NULL;
     7434    Utf8Str strSupHardeningLogArg;
    74987435#endif
    74997436
     7437    Utf8Str strAppOverride;
     7438#ifdef RT_OS_DARWIN /* Avoid Launch Services confusing this with the selector by using a helper app. */
     7439    strAppOverride = i_getExtraData(Utf8Str("VBoxInternal2/VirtualBoxVMAppOverride"));
     7440#endif
     7441
     7442    bool fUseVBoxSDS = false;
    75007443    Utf8Str strCanonicalName;
    7501 
     7444    if (false)
     7445    { }
    75027446#ifdef VBOX_WITH_QTGUI
    7503     if (   !strFrontend.compare("gui", Utf8Str::CaseInsensitive)
    7504         || !strFrontend.compare("GUI/Qt", Utf8Str::CaseInsensitive)
    7505         || !strFrontend.compare("separate", Utf8Str::CaseInsensitive)
    7506         || !strFrontend.compare("gui/separate", Utf8Str::CaseInsensitive)
    7507         || !strFrontend.compare("GUI/Qt/separate", Utf8Str::CaseInsensitive))
     7447    else if (   !strFrontend.compare("gui", Utf8Str::CaseInsensitive)
     7448             || !strFrontend.compare("GUI/Qt", Utf8Str::CaseInsensitive)
     7449             || !strFrontend.compare("separate", Utf8Str::CaseInsensitive)
     7450             || !strFrontend.compare("gui/separate", Utf8Str::CaseInsensitive)
     7451             || !strFrontend.compare("GUI/Qt/separate", Utf8Str::CaseInsensitive))
    75087452    {
    75097453        strCanonicalName = "GUI/Qt";
    7510 # ifdef RT_OS_DARWIN /* Avoid Launch Services confusing this with the selector by using a helper app. */
    7511         /* Modify the base path so that we don't need to use ".." below. */
    7512         RTPathStripTrailingSlash(szPath);
    7513         RTPathStripFilename(szPath);
    7514         cchBufLeft = strlen(szPath);
    7515         pszNamePart = szPath + cchBufLeft;
    7516         cchBufLeft = sizeof(szPath) - cchBufLeft;
    7517 
    7518 #  define OSX_APP_NAME "VirtualBoxVM"
    7519 #  define OSX_APP_PATH_FMT "/Resources/%s.app/Contents/MacOS/VirtualBoxVM"
    7520 
    7521         Utf8Str strAppOverride = i_getExtraData(Utf8Str("VBoxInternal2/VirtualBoxVMAppOverride"));
    7522         if (   strAppOverride.contains(".")
    7523             || strAppOverride.contains("/")
    7524             || strAppOverride.contains("\\")
    7525             || strAppOverride.contains(":"))
    7526             strAppOverride.setNull();
    7527         Utf8Str strAppPath;
    7528         if (!strAppOverride.isEmpty())
    7529         {
    7530             strAppPath = Utf8StrFmt(OSX_APP_PATH_FMT, strAppOverride.c_str());
    7531             Utf8Str strFullPath(szPath);
    7532             strFullPath.append(strAppPath);
    7533             /* there is a race, but people using this deserve the failure */
    7534             if (!RTFileExists(strFullPath.c_str()))
    7535                 strAppOverride.setNull();
    7536         }
    7537         if (strAppOverride.isEmpty())
    7538             strAppPath = Utf8StrFmt(OSX_APP_PATH_FMT, OSX_APP_NAME);
    7539         AssertReturn(cchBufLeft > strAppPath.length(), E_UNEXPECTED);
    7540         strcpy(pszNamePart, strAppPath.c_str());
    7541 # else
    7542         static const char s_szVirtualBox_exe[] = "VirtualBoxVM" HOSTSUFF_EXE;
    7543         Assert(cchBufLeft >= sizeof(s_szVirtualBox_exe));
    7544         strcpy(pszNamePart, s_szVirtualBox_exe);
    7545 # endif
    7546 
    7547         Utf8Str idStr = mData->mUuid.toString();
    7548         const char *apszArgs[] =
    7549         {
    7550             szPath,
    7551             "--comment", mUserData->s.strName.c_str(),
    7552             "--startvm", idStr.c_str(),
    7553             "--no-startvm-errormsgbox",
    7554             NULL, /* For "--separate". */
    7555             NULL, /* For "--sup-startup-log". */
    7556             NULL
    7557         };
    7558         unsigned iArg = 6;
    7559         if (fSeparate)
    7560             apszArgs[iArg++] = "--separate";
    7561         apszArgs[iArg++] = pszSupHardeningLogArg;
    7562 
    7563         vrc = RTProcCreate(szPath, apszArgs, env, 0, &pid);
    7564     }
    7565 #else /* !VBOX_WITH_QTGUI */
    7566     if (0)
    7567         ;
    7568 #endif /* VBOX_WITH_QTGUI */
    7569 
     7454        fUseVBoxSDS = true;
     7455    }
     7456#endif
     7457#ifdef VBOX_WITH_VBOXSDL
     7458    else if (   !strFrontend.compare("sdl", Utf8Str::CaseInsensitive)
     7459             || !strFrontend.compare("GUI/SDL", Utf8Str::CaseInsensitive)
     7460             || !strFrontend.compare("sdl/separate", Utf8Str::CaseInsensitive)
     7461             || !strFrontend.compare("GUI/SDL/separate", Utf8Str::CaseInsensitive))
     7462    {
     7463        strCanonicalName = "GUI/SDL";
     7464        fUseVBoxSDS = true;
     7465    }
     7466#endif
     7467#ifdef VBOX_WITH_HEADLESS
     7468    else if (   !strFrontend.compare("headless", Utf8Str::CaseInsensitive)
     7469             || !strFrontend.compare("capture", Utf8Str::CaseInsensitive)
     7470             || !strFrontend.compare("vrdp", Utf8Str::CaseInsensitive) /* Deprecated. Same as headless. */)
     7471    {
     7472        strCanonicalName = "headless";
     7473    }
     7474#endif
    75707475    else
    7571 
    7572 #ifdef VBOX_WITH_VBOXSDL
    7573     if (   !strFrontend.compare("sdl", Utf8Str::CaseInsensitive)
    7574         || !strFrontend.compare("GUI/SDL", Utf8Str::CaseInsensitive)
    7575         || !strFrontend.compare("sdl/separate", Utf8Str::CaseInsensitive)
    7576         || !strFrontend.compare("GUI/SDL/separate", Utf8Str::CaseInsensitive))
    7577     {
    7578         strCanonicalName = "GUI/SDL";
    7579         static const char s_szVBoxSDL_exe[] = "VBoxSDL" HOSTSUFF_EXE;
    7580         Assert(cchBufLeft >= sizeof(s_szVBoxSDL_exe));
    7581         strcpy(pszNamePart, s_szVBoxSDL_exe);
    7582 
    7583         Utf8Str idStr = mData->mUuid.toString();
    7584         const char *apszArgs[] =
    7585         {
    7586             szPath,
    7587             "--comment", mUserData->s.strName.c_str(),
    7588             "--startvm", idStr.c_str(),
    7589             NULL, /* For "--separate". */
    7590             NULL, /* For "--sup-startup-log". */
    7591             NULL
    7592         };
    7593         unsigned iArg = 5;
    7594         if (fSeparate)
    7595             apszArgs[iArg++] = "--separate";
    7596         apszArgs[iArg++] = pszSupHardeningLogArg;
    7597 
    7598         vrc = RTProcCreate(szPath, apszArgs, env, 0, &pid);
    7599     }
    7600 #else /* !VBOX_WITH_VBOXSDL */
    7601     if (0)
    7602         ;
    7603 #endif /* !VBOX_WITH_VBOXSDL */
    7604 
     7476        return setError(E_INVALIDARG, tr("Invalid frontend name: '%s'"), strFrontend.c_str());
     7477
     7478    Utf8Str idStr = mData->mUuid.toString();
     7479    Utf8Str const &strMachineName = mUserData->s.strName;
     7480    RTPROCESS pid = NIL_RTPROCESS;
     7481
     7482#if !defined(VBOX_WITH_SDS) || !defined(RT_OS_WINDOWS)
     7483    RT_NOREF(fUseVBoxSDS);
     7484#else
     7485    DWORD idCallerSession = ~(DWORD)0;
     7486    if (fUseVBoxSDS)
     7487    {
     7488        /*
     7489         * The VBoxSDS should be used for process launching the VM with
     7490         * GUI only if the caller and the VBoxSDS are in different Windows
     7491         * sessions and the caller in the interactive one.
     7492         */
     7493        fUseVBoxSDS = false;
     7494
     7495        /* Get windows session of the current process.  The process token used
     7496           due to several reasons:
     7497           1. The token is absent for the current thread except someone set it
     7498              for us.
     7499           2. Needs to get the id of the session where the process is started.
     7500           We only need to do this once, though. */
     7501        static DWORD s_idCurrentSession = ~(DWORD)0;
     7502        DWORD idCurrentSession = s_idCurrentSession;
     7503        if (idCurrentSession == ~(DWORD)0)
     7504        {
     7505            HANDLE hCurrentProcessToken = NULL;
     7506            if (OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY | TOKEN_READ, &hCurrentProcessToken))
     7507            {
     7508                DWORD cbIgn = 0;
     7509                if (GetTokenInformation(hCurrentProcessToken, TokenSessionId, &idCurrentSession, sizeof(idCurrentSession), &cbIgn))
     7510                    s_idCurrentSession = idCurrentSession;
     7511                else
     7512                {
     7513                    idCurrentSession = ~(DWORD)0;
     7514                    LogRelFunc(("GetTokenInformation/TokenSessionId on self failed: %u\n", GetLastError()));
     7515                }
     7516                CloseHandle(hCurrentProcessToken);
     7517            }
     7518            else
     7519                LogRelFunc(("OpenProcessToken/self failed: %u\n", GetLastError()));
     7520        }
     7521
     7522        /* get the caller's session */
     7523        HRESULT hrc = CoImpersonateClient();
     7524        if (SUCCEEDED(hrc))
     7525        {
     7526            HANDLE hCallerThreadToken;
     7527            if (OpenThreadToken(GetCurrentThread(), TOKEN_QUERY | TOKEN_READ,
     7528                                FALSE /* OpenAsSelf - for impersonation at SecurityIdentification level */,
     7529                                &hCallerThreadToken))
     7530            {
     7531                SetLastError(NO_ERROR);
     7532                DWORD cbIgn = 0;
     7533                if (GetTokenInformation(hCallerThreadToken, TokenSessionId, &idCallerSession, sizeof(DWORD), &cbIgn))
     7534                {
     7535                    /* Only need to use SDS if the session ID differs: */
     7536                    if (idCurrentSession != idCallerSession)
     7537                    {
     7538                        fUseVBoxSDS = false;
     7539
     7540                        /* Obtain the groups the access token belongs to so we can see if the session is interactive: */
     7541                        DWORD         cbTokenGroups = 0;
     7542                        PTOKEN_GROUPS pTokenGroups  = NULL;
     7543                        if (   !GetTokenInformation(hCallerThreadToken, TokenGroups, pTokenGroups, 0, &cbTokenGroups)
     7544                            && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
     7545                            pTokenGroups = (PTOKEN_GROUPS)RTMemTmpAllocZ(cbTokenGroups);
     7546                        if (GetTokenInformation(hCallerThreadToken, TokenGroups, pTokenGroups, cbTokenGroups, &cbTokenGroups))
     7547                        {
     7548                            /* Well-known interactive SID: SECURITY_INTERACTIVE_RID, S-1-5-4: */
     7549                            SID_IDENTIFIER_AUTHORITY sidIdNTAuthority = SECURITY_NT_AUTHORITY;
     7550                            PSID                     pInteractiveSid = NULL;
     7551                            if (AllocateAndInitializeSid(&sidIdNTAuthority, 1, 4, 0, 0, 0, 0, 0, 0, 0, &pInteractiveSid))
     7552                            {
     7553                                /* Iterate over the groups looking for the interactive SID: */
     7554                                fUseVBoxSDS = false;
     7555                                for (DWORD dwIndex = 0; dwIndex < pTokenGroups->GroupCount; dwIndex++)
     7556                                    if (EqualSid(pTokenGroups->Groups[dwIndex].Sid, pInteractiveSid))
     7557                                    {
     7558                                        fUseVBoxSDS = true;
     7559                                        break;
     7560                                    }
     7561                                FreeSid(pInteractiveSid);
     7562                            }
     7563                        }
     7564                        else
     7565                            LogRelFunc(("GetTokenInformation/TokenGroups failed: %u\n", GetLastError()));
     7566                        RTMemTmpFree(pTokenGroups);
     7567                    }
     7568                }
     7569                else
     7570                    LogRelFunc(("GetTokenInformation/TokenSessionId failed: %u\n", GetLastError()));
     7571                CloseHandle(hCallerThreadToken);
     7572            }
     7573            else
     7574                LogRelFunc(("OpenThreadToken/client failed: %u\n", GetLastError()));
     7575            CoRevertToSelf();
     7576        }
     7577        else
     7578            LogRelFunc(("CoImpersonateClient failed: %Rhrc\n", hrc));
     7579    }
     7580    if (fUseVBoxSDS)
     7581    {
     7582        /* connect to VBoxSDS */
     7583        ComPtr<IVirtualBoxSDS> pVBoxSDS;
     7584        HRESULT rc = pVBoxSDS.createLocalObject(CLSID_VirtualBoxSDS);
     7585        if (FAILED(rc))
     7586            return setError(rc, tr("Failed to start the machine '%s'. A connection to VBoxSDS cannot be established"),
     7587                            strMachineName.c_str());
     7588
     7589        /* By default the RPC_C_IMP_LEVEL_IDENTIFY is used for impersonation the client. It allows
     7590           ACL checking but restricts an access to system objects e.g. files. Call to CoSetProxyBlanket
     7591           elevates the impersonation level up to RPC_C_IMP_LEVEL_IMPERSONATE allowing the VBoxSDS
     7592           service to access the files. */
     7593        rc = CoSetProxyBlanket(pVBoxSDS,
     7594                               RPC_C_AUTHN_DEFAULT,
     7595                               RPC_C_AUTHZ_DEFAULT,
     7596                               COLE_DEFAULT_PRINCIPAL,
     7597                               RPC_C_AUTHN_LEVEL_DEFAULT,
     7598                               RPC_C_IMP_LEVEL_IMPERSONATE,
     7599                               NULL,
     7600                               EOAC_DEFAULT);
     7601        if (FAILED(rc))
     7602            return setError(rc, tr("Failed to start the machine '%s'. CoSetProxyBlanket failed"), strMachineName.c_str());
     7603        ULONG uPid = 0;
     7604        rc = pVBoxSDS->LaunchVMProcess(Bstr(idStr).raw(), Bstr(strMachineName).raw(), Bstr(strFrontend).raw(),
     7605                                       Bstr(strEnvironment).raw(), Bstr(strSupHardeningLogArg).raw(),
     7606                                       idCallerSession, &uPid);
     7607        if (FAILED(rc))
     7608            return setError(rc, tr("Failed to start the machine '%s'. Process creation failed"), strMachineName.c_str());
     7609        pid = (RTPROCESS)uPid;
     7610    }
    76057611    else
    7606 
    7607 #ifdef VBOX_WITH_HEADLESS
    7608     if (   !strFrontend.compare("headless", Utf8Str::CaseInsensitive)
    7609         || !strFrontend.compare("capture", Utf8Str::CaseInsensitive)
    7610         || !strFrontend.compare("vrdp", Utf8Str::CaseInsensitive) /* Deprecated. Same as headless. */
    7611        )
    7612     {
    7613         strCanonicalName = "headless";
    7614         /* On pre-4.0 the "headless" type was used for passing "--vrdp off" to VBoxHeadless to let it work in OSE,
    7615          * which did not contain VRDP server. In VBox 4.0 the remote desktop server (VRDE) is optional,
    7616          * and a VM works even if the server has not been installed.
    7617          * So in 4.0 the "headless" behavior remains the same for default VBox installations.
    7618          * Only if a VRDE has been installed and the VM enables it, the "headless" will work
    7619          * differently in 4.0 and 3.x.
    7620          */
    7621         static const char s_szVBoxHeadless_exe[] = "VBoxHeadless" HOSTSUFF_EXE;
    7622         Assert(cchBufLeft >= sizeof(s_szVBoxHeadless_exe));
    7623         strcpy(pszNamePart, s_szVBoxHeadless_exe);
    7624 
    7625         Utf8Str idStr = mData->mUuid.toString();
    7626         const char *apszArgs[] =
    7627         {
    7628             szPath,
    7629             "--comment", mUserData->s.strName.c_str(),
    7630             "--startvm", idStr.c_str(),
    7631             "--vrde", "config",
    7632             NULL, /* For "--capture". */
    7633             NULL, /* For "--sup-startup-log". */
    7634             NULL
    7635         };
    7636         unsigned iArg = 7;
    7637         if (!strFrontend.compare("capture", Utf8Str::CaseInsensitive))
    7638             apszArgs[iArg++] = "--capture";
    7639         apszArgs[iArg++] = pszSupHardeningLogArg;
    7640 
    7641 # ifdef RT_OS_WINDOWS
    7642         vrc = RTProcCreate(szPath, apszArgs, env, RTPROC_FLAGS_NO_WINDOW, &pid);
    7643 # else
    7644         vrc = RTProcCreate(szPath, apszArgs, env, 0, &pid);
    7645 # endif
    7646     }
    7647 #else /* !VBOX_WITH_HEADLESS */
    7648     if (0)
    7649         ;
    7650 #endif /* !VBOX_WITH_HEADLESS */
    7651     else
    7652     {
    7653         RTEnvDestroy(env);
    7654         return setError(E_INVALIDARG,
    7655                         tr("Invalid frontend name: '%s'"),
    7656                         strFrontend.c_str());
    7657     }
    7658 
    7659     RTEnvDestroy(env);
    7660 
    7661     if (RT_FAILURE(vrc))
    7662         return setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
    7663                             tr("Could not launch a process for the machine '%s' (%Rrc)"),
    7664                             mUserData->s.strName.c_str(), vrc);
    7665 
    7666     LogFlowThisFunc(("launched.pid=%d(0x%x)\n", pid, pid));
     7612#endif /* VBOX_WITH_VBOXSDS && RT_OS_WINDOWS */
     7613    {
     7614        int vrc = MachineLaunchVMCommonWorker(idStr, strMachineName, strFrontend, strEnvironment, strSupHardeningLogArg,
     7615                                              strAppOverride, 0 /*fFlags*/, NULL /*pvExtraData*/, pid);
     7616        if (RT_FAILURE(vrc))
     7617            return setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
     7618                                tr("Could not launch the VM process for the machine '%s' (%Rrc)"), strMachineName.c_str(), vrc);
     7619    }
     7620
     7621    LogRel(("Launched VM: %u pid: %u (%#x) frontend: %s name: %s\n",
     7622            idStr.c_str(), pid, pid, strFrontend.c_str(), strMachineName.c_str()));
    76677623
    76687624    if (!fSeparate)
  • trunk/src/VBox/Main/src-server/generic/AutostartDb-generic.cpp

    r76553 r80569  
    190190    rc = autostartModifyDb(true /* fAutostart */, true /* fAddVM */);
    191191    RTCritSectLeave(&this->CritSect);
    192 #elif defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
     192#elif defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_WINDOWS)
    193193    NOREF(pszVMId); /* Not needed */
    194194    rc = VINF_SUCCESS;
     
    210210    rc = autostartModifyDb(true /* fAutostart */, false /* fAddVM */);
    211211    RTCritSectLeave(&this->CritSect);
    212 #elif defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS)
     212#elif defined(RT_OS_DARWIN) || defined(RT_OS_SOLARIS) || defined(RT_OS_WINDOWS)
    213213    NOREF(pszVMId); /* Not needed */
    214214    rc = VINF_SUCCESS;
     
    230230    rc = autostartModifyDb(false /* fAutostart */, true /* fAddVM */);
    231231    RTCritSectLeave(&this->CritSect);
    232 #elif defined(RT_OS_DARWIN)
     232#elif defined(RT_OS_DARWIN) || defined(RT_OS_WINDOWS)
    233233    NOREF(pszVMId); /* Not needed */
    234234    rc = VINF_SUCCESS;
     
    250250    rc = autostartModifyDb(false /* fAutostart */, false /* fAddVM */);
    251251    RTCritSectLeave(&this->CritSect);
    252 #elif defined(RT_OS_DARWIN)
    253     NOREF(pszVMId); /* Not needed */
    254     rc = VINF_SUCCESS;
    255 #else
    256     NOREF(pszVMId);
    257     rc = VERR_NOT_SUPPORTED;
    258 #endif
    259 
    260     return rc;
    261 }
    262 
     252#elif defined(RT_OS_DARWIN) || defined (RT_OS_WINDOWS)
     253    NOREF(pszVMId); /* Not needed */
     254    rc = VINF_SUCCESS;
     255#else
     256    NOREF(pszVMId);
     257    rc = VERR_NOT_SUPPORTED;
     258#endif
     259
     260    return rc;
     261}
     262
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette