Example #1
0
void ParsedRegexpFilter_base::parse (const Bstr &aFilter)
{
    /// @todo (dmik) parse "rx:<regexp>" string
    //  note, that min/max checks must not be done, when the string
    //  begins with "rx:". These limits are for exact matching only!

    // empty or null string means any match (see #isMatch() below),
    // so we don't apply Min/Max restrictions in this case

    if (!aFilter.isEmpty())
    {
        size_t len = aFilter.length();

        if (mMinLen > 0 && len < mMinLen)
        {
            mNull = mValid = false;
            mErrorPosition = len;
            return;
        }

        if (mMaxLen > 0 && len > mMaxLen)
        {
            mNull = mValid = false;
            mErrorPosition = mMaxLen;
            return;
        }
    }

    mSimple = aFilter;
    mNull = false;
    mValid = true;
    mErrorPosition = 0;
}
STDMETHODIMP VRDEServer::COMGETTER(AuthLibrary) (BSTR *aLibrary)
{
    CheckComArgOutPointerValid(aLibrary);

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    Bstr bstrLibrary;

    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    bstrLibrary = mData->mAuthLibrary;
    alock.release();

    if (bstrLibrary.isEmpty())
    {
        /* Get the global setting. */
        ComPtr<ISystemProperties> systemProperties;
        HRESULT hrc = mParent->getVirtualBox()->COMGETTER(SystemProperties)(systemProperties.asOutParam());

        if (SUCCEEDED(hrc))
            hrc = systemProperties->COMGETTER(VRDEAuthLibrary)(bstrLibrary.asOutParam());

        if (FAILED(hrc))
            return setError(hrc, "failed to query the library setting\n");
    }

    bstrLibrary.cloneTo(aLibrary);

    return S_OK;
}
Example #3
0
/**
 * Determines the maximum balloon size to set for the specified machine.
 *
 * @return  unsigned long           Balloon size (in MB) to set, 0 if no ballooning required.
 * @param   rptrMachine             Pointer to interface of specified machine.
 */
static unsigned long balloonGetMaxSize(const ComPtr<IMachine> &rptrMachine)
{
    /*
     * Try to retrieve the balloon maximum size via the following order:
     *  - command line parameter ("--balloon-max")
     *  Legacy (VBoxBalloonCtrl):
     *  - per-VM parameter ("VBoxInternal/Guest/BalloonSizeMax")
     *  Global:
     *  - global parameter ("VBoxInternal/Guest/BalloonSizeMax")
     *  New:
     *  - per-VM parameter ("VBoxInternal2/Watchdog/BalloonCtrl/BalloonSizeMax")
     *
     *  By default (e.g. if none of above is set), ballooning is disabled.
     */
    unsigned long ulBalloonMax = g_ulMemoryBalloonMaxMB;
    if (!ulBalloonMax)
    {
        int vrc = cfgGetValueULong(g_pVirtualBox, rptrMachine,
                                  "VBoxInternal/Guest/BalloonSizeMax", "VBoxInternal/Guest/BalloonSizeMax", &ulBalloonMax, 0 /* Ballooning disabled */);
        if (RT_FAILURE(vrc))
        {
            /* Try (new) VBoxWatch per-VM approach. */
            Bstr strValue;
            HRESULT rc = rptrMachine->GetExtraData(Bstr("VBoxInternal2/Watchdog/BalloonCtrl/BalloonSizeMax").raw(),
                                                   strValue.asOutParam());
            if (   SUCCEEDED(rc)
                && !strValue.isEmpty())
            {
                ulBalloonMax = Utf8Str(strValue).toUInt32();
            }
        }
    }

    return ulBalloonMax;
}
Example #4
0
/**
 * Sets the general Guest Additions information like
 * API (interface) version and OS type.  Gets called by
 * vmmdevUpdateGuestInfo.
 *
 * @param aInterfaceVersion
 * @param aOsType
 */
void Guest::setAdditionsInfo(Bstr aInterfaceVersion, VBOXOSTYPE aOsType)
{
    AutoCaller autoCaller(this);
    AssertComRCReturnVoid(autoCaller.rc());

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    /*
     * Note: The Guest Additions API (interface) version is deprecated
     * and will not be used anymore!  We might need it to at least report
     * something as version number if *really* ancient Guest Additions are
     * installed (without the guest version + revision properties having set).
     */
    mData.mInterfaceVersion = aInterfaceVersion;

    /*
     * Older Additions rely on the Additions API version whether they
     * are assumed to be active or not.  Since newer Additions do report
     * the Additions version *before* calling this function (by calling
     * VMMDevReportGuestInfo2, VMMDevReportGuestStatus, VMMDevReportGuestInfo,
     * in that order) we can tell apart old and new Additions here. Old
     * Additions never would set VMMDevReportGuestInfo2 (which set mData.mAdditionsVersion)
     * so they just rely on the aInterfaceVersion string (which gets set by
     * VMMDevReportGuestInfo).
     *
     * So only mark the Additions as being active (run level = system) when we
     * don't have the Additions version set.
     */
    if (mData.mAdditionsVersion.isEmpty())
    {
        if (aInterfaceVersion.isEmpty())
            mData.mAdditionsRunLevel = AdditionsRunLevelType_None;
        else
        {
            mData.mAdditionsRunLevel = AdditionsRunLevelType_System;

            /*
             * To keep it compatible with the old Guest Additions behavior we need to set the
             * "graphics" (feature) facility to active as soon as we got the Guest Additions
             * interface version.
             */
            facilityUpdate(VBoxGuestFacilityType_Graphics, VBoxGuestFacilityStatus_Active);
        }
    }

    /*
     * Older Additions didn't have this finer grained capability bit,
     * so enable it by default. Newer Additions will not enable this here
     * and use the setSupportedFeatures function instead.
     */
    facilityUpdate(VBoxGuestFacilityType_Graphics, facilityIsActive(VBoxGuestFacilityType_VBoxGuestDriver) ?
                   VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive);

    /*
     * Note! There is a race going on between setting mAdditionsRunLevel and
     * mSupportsGraphics here and disabling/enabling it later according to
     * its real status when using new(er) Guest Additions.
     */
    mData.mOSTypeId = Global::OSTypeId (aOsType);
}
HRESULT HostNetworkInterface::i_setVirtualBox(VirtualBox *pVirtualBox)
{
    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    AssertReturn(mVirtualBox != pVirtualBox, S_OK);

    unconst(mVirtualBox) = pVirtualBox;

#if !defined(RT_OS_WINDOWS)
    /* If IPv4 address hasn't been initialized */
    if (m.IPAddress == 0 && mIfType == HostNetworkInterfaceType_HostOnly)
    {
        Bstr tmpAddr, tmpMask;
        HRESULT hrc = mVirtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPAddress",
                                                        mInterfaceName.c_str()).raw(),
                                                tmpAddr.asOutParam());
        if (FAILED(hrc) || tmpAddr.isEmpty())
            tmpAddr = getDefaultIPv4Address(mInterfaceName);

        hrc = mVirtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPNetMask",
                                                mInterfaceName.c_str()).raw(),
                                        tmpMask.asOutParam());
        if (FAILED(hrc) || tmpMask.isEmpty())
            tmpMask = Bstr(VBOXNET_IPV4MASK_DEFAULT);

        m.IPAddress = inet_addr(Utf8Str(tmpAddr).c_str());
        m.networkMask = inet_addr(Utf8Str(tmpMask).c_str());
    }

    if (m.IPV6Address.isEmpty())
    {
        Bstr bstrIPV4Addr;
        Bstr tmpPrefixLen;
        HRESULT hrc = mVirtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6Address",
                                                        mInterfaceName.c_str()).raw(),
                                                bstrIPV4Addr.asOutParam());
        if (SUCCEEDED(hrc))
        {
            m.IPV6Address = bstrIPV4Addr;
            if (!m.IPV6Address.isEmpty())
            {
                hrc = mVirtualBox->GetExtraData(BstrFmt("HostOnly/%s/IPV6PrefixLen",
                                                        mInterfaceName.c_str()).raw(),
                                                tmpPrefixLen.asOutParam());
                if (SUCCEEDED(hrc) && !tmpPrefixLen.isEmpty())
                    m.IPV6NetworkMaskPrefixLength = Utf8Str(tmpPrefixLen).toUInt32();
                else
                    m.IPV6NetworkMaskPrefixLength = 64;
            }
        }
    }
#endif

    return S_OK;
}
static int handleGetGuestProperty(HandlerArg *a)
{
    HRESULT rc = S_OK;

    bool verbose = false;
    if (    a->argc == 3
        &&  (   !strcmp(a->argv[2], "--verbose")
             || !strcmp(a->argv[2], "-verbose")))
        verbose = true;
    else if (a->argc != 2)
        return errorSyntax(USAGE_GUESTPROPERTY, "Incorrect parameters");

    ComPtr<IMachine> machine;
    CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
                                           machine.asOutParam()));
    if (machine)
    {
        /* open a session for the VM - new or existing */
        CHECK_ERROR_RET(machine, LockMachine(a->session, LockType_Shared), 1);

        /* get the mutable session machine */
        a->session->COMGETTER(Machine)(machine.asOutParam());

        Bstr value;
        LONG64 i64Timestamp;
        Bstr flags;
        CHECK_ERROR(machine, GetGuestProperty(Bstr(a->argv[1]).raw(),
                                              value.asOutParam(),
                                              &i64Timestamp, flags.asOutParam()));
        if (value.isEmpty())
            RTPrintf("No value set!\n");
        else
            RTPrintf("Value: %ls\n", value.raw());
        if (!value.isEmpty() && verbose)
        {
            RTPrintf("Timestamp: %lld\n", i64Timestamp);
            RTPrintf("Flags: %ls\n", flags.raw());
        }
    }
    return SUCCEEDED(rc) ? 0 : 1;
}
Example #7
0
STDMETHODIMP Guest::COMGETTER(AdditionsVersion)(BSTR *a_pbstrAdditionsVersion)
{
    CheckComArgOutPointerValid(a_pbstrAdditionsVersion);

    AutoCaller autoCaller(this);
    HRESULT hrc = autoCaller.rc();
    if (SUCCEEDED(hrc))
    {
        AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);

        /*
         * Return the ReportGuestInfo2 version info if available.
         */
        if (   !mData.mAdditionsVersionNew.isEmpty()
            || mData.mAdditionsRunLevel <= AdditionsRunLevelType_None)
            mData.mAdditionsVersionNew.cloneTo(a_pbstrAdditionsVersion);
        else
        {
            /*
             * If we're running older guest additions (< 3.2.0) try get it from
             * the guest properties.  Detected switched around Version and
             * Revision in early 3.1.x releases (see r57115).
             */
            ComPtr<IMachine> ptrMachine = mParent->machine();
            alock.release(); /* No need to hold this during the IPC fun. */

            Bstr bstr;
            hrc = ptrMachine->GetGuestPropertyValue(Bstr("/VirtualBox/GuestAdd/Version").raw(), bstr.asOutParam());
            if (   SUCCEEDED(hrc)
                && !bstr.isEmpty())
            {
                Utf8Str str(bstr);
                if (str.count('.') == 0)
                    hrc = ptrMachine->GetGuestPropertyValue(Bstr("/VirtualBox/GuestAdd/Revision").raw(), bstr.asOutParam());
                str = bstr;
                if (str.count('.') != 2)
                    hrc = E_FAIL;
            }

            if (SUCCEEDED(hrc))
                bstr.detachTo(a_pbstrAdditionsVersion);
            else
            {
                /* Returning 1.4 is better than nothing. */
                alock.acquire();
                mData.mInterfaceVersion.cloneTo(a_pbstrAdditionsVersion);
                hrc = S_OK;
            }
        }
    }
    return hrc;
}
static DECLCALLBACK(int) VBoxModAPIMonitorMain(void)
{
    static uint64_t uLastRun = 0;
    uint64_t uNow = RTTimeProgramMilliTS();
    uint64_t uDelta = uNow - uLastRun;
    if (uDelta < 1000) /* Only check every second (or later). */
        return VINF_SUCCESS;
    uLastRun = uNow;

    int vrc = VINF_SUCCESS;
    HRESULT rc;

#ifdef DEBUG
    serviceLogVerbose(("apimon: Checking for API heartbeat (%RU64ms) ...\n",
                       g_ulAPIMonIslnTimeoutMS));
#endif

    do
    {
        Bstr strHeartbeat;
        CHECK_ERROR_BREAK(g_pVirtualBox, GetExtraData(Bstr("Watchdog/APIMonitor/Heartbeat").raw(),
                                                      strHeartbeat.asOutParam()));
        if (   SUCCEEDED(rc)
            && !strHeartbeat.isEmpty()
            && g_strAPIMonIslnLastBeat.compare(strHeartbeat, Bstr::CaseSensitive))
        {
            serviceLogVerbose(("apimon: API heartbeat received, resetting timeout\n"));

            g_uAPIMonIslnLastBeatMS = 0;
            g_strAPIMonIslnLastBeat = strHeartbeat;
        }
        else
        {
            g_uAPIMonIslnLastBeatMS += uDelta;
            if (g_uAPIMonIslnLastBeatMS > g_ulAPIMonIslnTimeoutMS)
            {
                serviceLogVerbose(("apimon: No API heartbeat within time received (%RU64ms)\n",
                                   g_ulAPIMonIslnTimeoutMS));

                vrc = apimonTrigger(g_enmAPIMonIslnResp);
                g_uAPIMonIslnLastBeatMS = 0;
            }
        }
    } while (0);

    if (FAILED(rc))
        vrc = VERR_COM_IPRT_ERROR;

    return vrc;
}
Example #9
0
int NetIfRemoveHostOnlyNetworkInterface(VirtualBox *pVirtualBox, IN_GUID aId,
                                        IProgress **aProgress)
{
#if defined(RT_OS_LINUX) || defined(RT_OS_DARWIN) || defined(RT_OS_FREEBSD)
    /* create a progress object */
    ComObjPtr<Progress> progress;
    progress.createObject();
    ComPtr<IHost> host;
    int rc = VINF_SUCCESS;
    HRESULT hr = pVirtualBox->COMGETTER(Host)(host.asOutParam());
    if (SUCCEEDED(hr))
    {
        Bstr ifname;
        ComPtr<IHostNetworkInterface> iface;
        if (FAILED(host->FindHostNetworkInterfaceById(Guid(aId).toUtf16().raw(), iface.asOutParam())))
            return VERR_INVALID_PARAMETER;
        iface->COMGETTER(Name)(ifname.asOutParam());
        if (ifname.isEmpty())
            return VERR_INTERNAL_ERROR;

        rc = progress->init(pVirtualBox, host,
                            Bstr("Removing host network interface").raw(),
                            FALSE /* aCancelable */);
        if (SUCCEEDED(rc))
        {
            progress.queryInterfaceTo(aProgress);
            rc = NetIfAdpCtl(Utf8Str(ifname).c_str(), "remove", NULL, NULL);
            if (RT_FAILURE(rc))
                progress->i_notifyComplete(E_FAIL,
                                           COM_IIDOF(IHostNetworkInterface),
                                           HostNetworkInterface::getStaticComponentName(),
                                           "Failed to execute '" VBOXNETADPCTL_NAME "' (exit status: %d)", rc);
            else
                progress->i_notifyComplete(S_OK);
        }
    }
    else
    {
        progress->i_notifyComplete(hr);
        rc = VERR_INTERNAL_ERROR;
    }
    return rc;
#else
    NOREF(pVirtualBox);
    NOREF(aId);
    NOREF(aProgress);
    return VERR_NOT_IMPLEMENTED;
#endif
}
/**
 * Determines the requested balloon size to set for the specified machine.
 *
 * @return  Requested ballooning size (in MB), 0 if ballooning should be disabled.
 * @param   pMachine                Machine to determine maximum ballooning size for.
 */
static uint32_t balloonGetRequestedSize(PVBOXWATCHDOG_MACHINE pMachine)
{
    const ComPtr<IMachine> &rptrMachine = pMachine->machine;

    /*
     * The maximum balloning size can be set
     * - via per-VM extra-data ("VBoxInternal2/Watchdog/BalloonCtrl/BalloonSizeMax")
     * - via per-VM extra-data (legacy) ("VBoxInternal/Guest/BalloonSizeMax")
     *
     * Precedence from top to bottom.
     */
    uint32_t cMbBalloonReq = 0;
    char szSource[64];

    Bstr strValue;
    HRESULT hr = rptrMachine->GetExtraData(Bstr("VBoxInternal2/Watchdog/BalloonCtrl/BalloonSizeMax").raw(),
                                           strValue.asOutParam());
    if (   SUCCEEDED(hr)
        && strValue.isNotEmpty())
    {
        cMbBalloonReq = Utf8Str(strValue).toUInt32();
        if (g_fVerbose)
            RTStrPrintf(szSource, sizeof(szSource), "per-VM extra-data");
    }
    else
    {
        hr = rptrMachine->GetExtraData(Bstr("VBoxInternal/Guest/BalloonSizeMax").raw(),
                                       strValue.asOutParam());
        if (   SUCCEEDED(hr)
            && strValue.isNotEmpty())
        {
            cMbBalloonReq = Utf8Str(strValue).toUInt32();
            if (g_fVerbose)
                RTStrPrintf(szSource, sizeof(szSource), "per-VM extra-data (legacy)");
        }
    }

    if (   FAILED(hr)
        || strValue.isEmpty())
    {
        cMbBalloonReq = 0;
        if (g_fVerbose)
            RTStrPrintf(szSource, sizeof(szSource), "none (disabled)");
    }

    serviceLogVerbose(("[%ls] Requested balloning size is (%s): %RU32MB\n", pMachine->strName.raw(), szSource, cMbBalloonReq));
    return cMbBalloonReq;
}
Example #11
0
/**
 * Sets the Guest Additions version information details.
 * Gets called by vmmdevUpdateGuestInfo2.
 *
 * @param aAdditionsVersion
 * @param aVersionName
 */
void Guest::setAdditionsInfo2(Bstr aAdditionsVersion, Bstr aVersionName, Bstr aRevision)
{
    AutoCaller autoCaller(this);
    AssertComRCReturnVoid(autoCaller.rc());

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);

    if (!aVersionName.isEmpty())
        /*
         * aVersionName could be "x.y.z_BETA1_FOOBAR", so append revision manually to
         * become "x.y.z_BETA1_FOOBAR r12345".
         */
        mData.mAdditionsVersion = BstrFmt("%ls r%ls", aVersionName.raw(), aRevision.raw());
    else /* aAdditionsVersion is in x.y.zr12345 format. */
        mData.mAdditionsVersion = aAdditionsVersion;
}
Example #12
0
void GluePrintErrorInfo(const com::ErrorInfo &info)
{
    bool haveResultCode = false;
#if defined (RT_OS_WIN)
    haveResultCode = info.isFullAvailable();
    bool haveComponent = true;
    bool haveInterfaceID = true;
#else /* defined (RT_OS_WIN) */
    haveResultCode = true;
    bool haveComponent = info.isFullAvailable();
    bool haveInterfaceID = info.isFullAvailable();
#endif

    Utf8Str str;
    RTCList<Utf8Str> comp;

    Bstr bstrDetailsText = info.getText();
    if (!bstrDetailsText.isEmpty())
        str = Utf8StrFmt("%ls\n",
                         bstrDetailsText.raw());
    if (haveResultCode)
        comp.append(Utf8StrFmt("code %Rhrc (0x%RX32)",
                               info.getResultCode(),
                               info.getResultCode()));
    if (haveComponent)
        comp.append(Utf8StrFmt("component %ls",
                               info.getComponent().raw()));
    if (haveInterfaceID)
        comp.append(Utf8StrFmt("interface %ls",
                               info.getInterfaceName().raw()));
    if (!info.getCalleeName().isEmpty())
        comp.append(Utf8StrFmt("callee %ls",
                               info.getCalleeName().raw()));

    if (comp.size() > 0)
    {
        str += "Details: ";
        for (size_t i = 0; i < comp.size() - 1; ++i)
            str += comp.at(i) + ", ";
        str += comp.last();
        str += "\n";
    }

    // print and log
    RTMsgError("%s", str.c_str());
    Log(("ERROR: %s", str.c_str()));
}
HRESULT Guest::getAdditionsVersion(com::Utf8Str &aAdditionsVersion)
{
    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    HRESULT hrc = S_OK;

    /*
     * Return the ReportGuestInfo2 version info if available.
     */
    if (   !mData.mAdditionsVersionNew.isEmpty()
         || mData.mAdditionsRunLevel <= AdditionsRunLevelType_None)
        aAdditionsVersion = mData.mAdditionsVersionNew;
    else
    {
        /*
         * If we're running older guest additions (< 3.2.0) try get it from
         * the guest properties.  Detected switched around Version and
         * Revision in early 3.1.x releases (see r57115).
         */
        ComPtr<IMachine> ptrMachine = mParent->i_machine();
        alock.release(); /* No need to hold this during the IPC fun. */

        Bstr bstr;
        hrc = ptrMachine->GetGuestPropertyValue(Bstr("/VirtualBox/GuestAdd/Version").raw(), bstr.asOutParam());
        if (   SUCCEEDED(hrc)
            && !bstr.isEmpty())
        {
            Utf8Str str(bstr);
            if (str.count('.') == 0)
                hrc = ptrMachine->GetGuestPropertyValue(Bstr("/VirtualBox/GuestAdd/Revision").raw(), bstr.asOutParam());
            str = bstr;
            if (str.count('.') != 2)
                hrc = E_FAIL;
        }

        if (SUCCEEDED(hrc))
            aAdditionsVersion = bstr;
        else
        {
            /* Returning 1.4 is better than nothing. */
            alock.acquire();
            aAdditionsVersion = mData.mInterfaceVersion;
            hrc = S_OK;
        }
    }
    return hrc;
}
/**
 * Initializes the host object.
 *
 * @returns COM result indicator
 * @param   aInterfaceName name of the network interface
 * @param   aGuid GUID of the host network interface
 */
HRESULT HostNetworkInterface::init(Bstr aInterfaceName, Guid aGuid, HostNetworkInterfaceType_T ifType)
{
    LogFlowThisFunc(("aInterfaceName={%ls}, aGuid={%s}\n",
                      aInterfaceName.raw(), aGuid.toString().c_str()));

    ComAssertRet(!aInterfaceName.isEmpty(), E_INVALIDARG);
    ComAssertRet(!aGuid.isEmpty(), E_INVALIDARG);

    /* Enclose the state transition NotReady->InInit->Ready */
    AutoInitSpan autoInitSpan(this);
    AssertReturn(autoInitSpan.isOk(), E_FAIL);

    unconst(mInterfaceName) = aInterfaceName;
    unconst(mGuid) = aGuid;
    mIfType = ifType;

    /* Confirm a successful initialization */
    autoInitSpan.setSucceeded();

    return S_OK;
}
Example #15
0
void ParsedBoolFilter::parse (const Bstr &aFilter)
{
    mNull = false;
    mValid = true;
    mErrorPosition = 0;

    if (aFilter.isEmpty())
    {
        mValueAny = true;
        mValue = false;
    }
    else
    {
        mValueAny = false;
        if (aFilter == L"true" || aFilter == L"yes" || aFilter == L"1")
            mValue = true;
        else
        if (aFilter == L"false" || aFilter == L"no" || aFilter == L"0")
            mValue = false;
        else
            mValid = false;
    }
}
/**
 * Determines the maximum balloon size to set for the specified machine.
 *
 * @return  Maximum ballooning size (in MB), 0 if no maximum set.
 * @param   pMachine                Machine to determine maximum ballooning size for.
 */
static uint32_t balloonGetMaxSize(PVBOXWATCHDOG_MACHINE pMachine)
{
    /*
     * Is a maximum ballooning size set? Make sure we're within bounds.
     *
     * The maximum balloning size can be set
     * - via global extra-data ("VBoxInternal/Guest/BalloonSizeMax")
     * - via command line ("--balloon-max")
     *
     * Precedence from top to bottom.
     */
    uint32_t cMbBalloonMax = 0;
    char szSource[64];

    Bstr strValue;
    HRESULT hr = g_pVirtualBox->GetExtraData(Bstr("VBoxInternal/Guest/BalloonSizeMax").raw(),
                                             strValue.asOutParam());
    if (   SUCCEEDED(hr)
        && strValue.isNotEmpty())
    {
        cMbBalloonMax = Utf8Str(strValue).toUInt32();
        if (g_fVerbose)
            RTStrPrintf(szSource, sizeof(szSource), "global extra-data");
    }

    if (strValue.isEmpty())
    {
        Assert(cMbBalloonMax == 0);

        cMbBalloonMax = g_cMbMemoryBalloonMax;
        if (g_fVerbose)
            RTStrPrintf(szSource, sizeof(szSource), "command line");
    }

    serviceLogVerbose(("[%ls] Maximum balloning size is (%s): %RU32MB\n", pMachine->strName.raw(), szSource, cMbBalloonMax));
    return cMbBalloonMax;
}
/**
 * Removes a specified machine from the list of handled machines.
 * Does not do locking -- needs to be done by caller!
 *
 * @return  IPRT status code.
 * @param   strUuid                 UUID of the specified machine.
 */
static int machineRemove(const Bstr &strUuid)
{
    AssertReturn(!strUuid.isEmpty(), VERR_INVALID_PARAMETER);
    int rc = VINF_SUCCESS;

    mapVMIter it = g_mapVM.find(strUuid);
    if (it != g_mapVM.end())
    {
        int rc2 = machineDestroy(strUuid);
        if (RT_FAILURE(rc))
        {
            serviceLog(("Machine \"%ls\" failed to destroy, rc=%Rc\n"));
            if (RT_SUCCESS(rc))
                rc = rc2;
        }
    }
    else
    {
        serviceLogVerbose(("Warning: Removing not added machine \"%ls\"\n", strUuid.raw()));
        rc = VERR_NOT_FOUND;
    }

    return rc;
}
static int machineDestroy(const Bstr &strUuid)
{
    AssertReturn(!strUuid.isEmpty(), VERR_INVALID_PARAMETER);
    int rc = VINF_SUCCESS;

    /* Let all modules know. */
    for (unsigned j = 0; j < RT_ELEMENTS(g_aModules); j++)
        if (g_aModules[j].fEnabled)
        {
            int rc2 = g_aModules[j].pDesc->pfnOnMachineUnregistered(strUuid);
            if (RT_FAILURE(rc2))
                serviceLog("OnMachineUnregistered: Module '%s' reported an error: %Rrc\n",
                           g_aModules[j].pDesc->pszName, rc);
            /* Keep going. */
        }

    /* Must log before erasing the iterator because of the UUID ref! */
    serviceLogVerbose(("Removing machine \"%ls\"\n", strUuid.raw()));

    try
    {
        mapVMIter itVM = g_mapVM.find(strUuid);
        Assert(itVM != g_mapVM.end());

        /* Remove machine from group(s). */
        mapGroupsIterConst itGroups = itVM->second.groups.begin();
        while (itGroups != itVM->second.groups.end())
        {
            mapGroupIter itGroup = g_mapGroup.find(itGroups->first);
            Assert(itGroup != g_mapGroup.end());

            vecGroupMembers vecMembers = itGroup->second;
            vecGroupMembersIter itMember = std::find(vecMembers.begin(),
                                                     vecMembers.end(),
                                                     strUuid);
            Assert(itMember != vecMembers.end());
            vecMembers.erase(itMember);

            serviceLogVerbose(("Group \"%s\" has %ld machines left\n",
                               itGroup->first.c_str(), vecMembers.size()));
            if (!vecMembers.size())
            {
                serviceLogVerbose(("Deleting group \"%s\"\n", itGroup->first.c_str()));
                g_mapGroup.erase(itGroup);
            }

            ++itGroups;
        }

#ifndef VBOX_WATCHDOG_GLOBAL_PERFCOL
        itVM->second.collector.setNull();
#endif
        itVM->second.machine.setNull();

        /*
         * Remove machine from map.
         */
        g_mapVM.erase(itVM);
    }
    catch (...)
    {
        AssertFailed();
    }

    return rc;
}
int handleGetExtraData(HandlerArg *a)
{
    HRESULT rc = S_OK;

    if (a->argc != 2)
        return errorSyntax(USAGE_GETEXTRADATA, "Incorrect number of parameters");

    /* global data? */
    if (!strcmp(a->argv[0], "global"))
    {
        /* enumeration? */
        if (!strcmp(a->argv[1], "enumerate"))
        {
            SafeArray<BSTR> aKeys;
            CHECK_ERROR(a->virtualBox, GetExtraDataKeys(ComSafeArrayAsOutParam(aKeys)));

            for (size_t i = 0;
                 i < aKeys.size();
                 ++i)
            {
                Bstr bstrKey(aKeys[i]);
                Bstr bstrValue;
                CHECK_ERROR(a->virtualBox, GetExtraData(bstrKey.raw(),
                                                        bstrValue.asOutParam()));

                RTPrintf("Key: %ls, Value: %ls\n", bstrKey.raw(), bstrValue.raw());
            }
        }
        else
        {
            Bstr value;
            CHECK_ERROR(a->virtualBox, GetExtraData(Bstr(a->argv[1]).raw(),
                                                    value.asOutParam()));
            if (!value.isEmpty())
                RTPrintf("Value: %ls\n", value.raw());
            else
                RTPrintf("No value set!\n");
        }
    }
    else
    {
        ComPtr<IMachine> machine;
        CHECK_ERROR(a->virtualBox, FindMachine(Bstr(a->argv[0]).raw(),
                                               machine.asOutParam()));
        if (machine)
        {
            /* enumeration? */
            if (!strcmp(a->argv[1], "enumerate"))
            {
                SafeArray<BSTR> aKeys;
                CHECK_ERROR(machine, GetExtraDataKeys(ComSafeArrayAsOutParam(aKeys)));

                for (size_t i = 0;
                    i < aKeys.size();
                    ++i)
                {
                    Bstr bstrKey(aKeys[i]);
                    Bstr bstrValue;
                    CHECK_ERROR(machine, GetExtraData(bstrKey.raw(),
                                                      bstrValue.asOutParam()));

                    RTPrintf("Key: %ls, Value: %ls\n", bstrKey.raw(), bstrValue.raw());
                }
            }
            else
            {
                Bstr value;
                CHECK_ERROR(machine, GetExtraData(Bstr(a->argv[1]).raw(),
                                                  value.asOutParam()));
                if (!value.isEmpty())
                    RTPrintf("Value: %ls\n", value.raw());
                else
                    RTPrintf("No value set!\n");
            }
        }
    }
    return SUCCEEDED(rc) ? 0 : 1;
}
int handleCloneVM(HandlerArg *a)
{
    HRESULT                        rc;
    const char                    *pszSrcName       = NULL;
    const char                    *pszSnapshotName  = NULL;
    CloneMode_T                    mode             = CloneMode_MachineState;
    com::SafeArray<CloneOptions_T> options;
    const char                    *pszTrgName       = NULL;
    const char                    *pszTrgBaseFolder = NULL;
    bool                           fRegister        = false;
    Bstr                           bstrUuid;
    com::SafeArray<BSTR> groups;

    int c;
    RTGETOPTUNION ValueUnion;
    RTGETOPTSTATE GetState;
    // start at 0 because main() has hacked both the argc and argv given to us
    RTGetOptInit(&GetState, a->argc, a->argv, g_aCloneVMOptions, RT_ELEMENTS(g_aCloneVMOptions),
                 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
    while ((c = RTGetOpt(&GetState, &ValueUnion)))
    {
        switch (c)
        {
            case 's':   // --snapshot
                pszSnapshotName = ValueUnion.psz;
                break;

            case 'n':   // --name
                pszTrgName = ValueUnion.psz;
                break;

            case 'g':   // --groups
                parseGroups(ValueUnion.psz, &groups);
                break;

            case 'p':   // --basefolder
                pszTrgBaseFolder = ValueUnion.psz;
                break;

            case 'm':   // --mode
                if (RT_FAILURE(parseCloneMode(ValueUnion.psz, &mode)))
                    return errorArgument("Invalid clone mode '%s'\n", ValueUnion.psz);
                break;

            case 'o':   // --options
                if (RT_FAILURE(parseCloneOptions(ValueUnion.psz, &options)))
                    return errorArgument("Invalid clone options '%s'\n", ValueUnion.psz);
                break;

            case 'u':   // --uuid
                bstrUuid = Guid(ValueUnion.Uuid).toUtf16().raw();
                break;

            case 'r':   // --register
                fRegister = true;
                break;

            case VINF_GETOPT_NOT_OPTION:
                if (!pszSrcName)
                    pszSrcName = ValueUnion.psz;
                else
                    return errorSyntax(USAGE_CLONEVM, "Invalid parameter '%s'", ValueUnion.psz);
                break;

            default:
                return errorGetOpt(USAGE_CLONEVM, c, &ValueUnion);
        }
    }

    /* Check for required options */
    if (!pszSrcName)
        return errorSyntax(USAGE_CLONEVM, "VM name required");

    /* Get the machine object */
    ComPtr<IMachine> srcMachine;
    CHECK_ERROR_RET(a->virtualBox, FindMachine(Bstr(pszSrcName).raw(),
                                               srcMachine.asOutParam()),
                    RTEXITCODE_FAILURE);

    /* If a snapshot name/uuid was given, get the particular machine of this
     * snapshot. */
    if (pszSnapshotName)
    {
        ComPtr<ISnapshot> srcSnapshot;
        CHECK_ERROR_RET(srcMachine, FindSnapshot(Bstr(pszSnapshotName).raw(),
                                                 srcSnapshot.asOutParam()),
                        RTEXITCODE_FAILURE);
        CHECK_ERROR_RET(srcSnapshot, COMGETTER(Machine)(srcMachine.asOutParam()),
                        RTEXITCODE_FAILURE);
    }

    /* Default name necessary? */
    if (!pszTrgName)
        pszTrgName = RTStrAPrintf2("%s Clone", pszSrcName);

    Bstr createFlags;
    if (!bstrUuid.isEmpty())
        createFlags = BstrFmt("UUID=%ls", bstrUuid.raw());
    Bstr bstrPrimaryGroup;
    if (groups.size())
        bstrPrimaryGroup = groups[0];
    Bstr bstrSettingsFile;
    CHECK_ERROR_RET(a->virtualBox,
                    ComposeMachineFilename(Bstr(pszTrgName).raw(),
                                           bstrPrimaryGroup.raw(),
                                           createFlags.raw(),
                                           Bstr(pszTrgBaseFolder).raw(),
                                           bstrSettingsFile.asOutParam()),
                    RTEXITCODE_FAILURE);

    ComPtr<IMachine> trgMachine;
    CHECK_ERROR_RET(a->virtualBox, CreateMachine(bstrSettingsFile.raw(),
                                                 Bstr(pszTrgName).raw(),
                                                 ComSafeArrayAsInParam(groups),
                                                 NULL,
                                                 createFlags.raw(),
                                                 trgMachine.asOutParam()),
                    RTEXITCODE_FAILURE);

    /* Start the cloning */
    ComPtr<IProgress> progress;
    CHECK_ERROR_RET(srcMachine, CloneTo(trgMachine,
                                        mode,
                                        ComSafeArrayAsInParam(options),
                                        progress.asOutParam()),
                    RTEXITCODE_FAILURE);
    rc = showProgress(progress);
    CHECK_PROGRESS_ERROR_RET(progress, ("Clone VM failed"), RTEXITCODE_FAILURE);

    if (fRegister)
        CHECK_ERROR_RET(a->virtualBox, RegisterMachine(trgMachine), RTEXITCODE_FAILURE);

    Bstr bstrNewName;
    CHECK_ERROR_RET(trgMachine, COMGETTER(Name)(bstrNewName.asOutParam()), RTEXITCODE_FAILURE);
    RTPrintf("Machine has been successfully cloned as \"%ls\"\n", bstrNewName.raw());

    return RTEXITCODE_SUCCESS;
}
int handleCreateVM(HandlerArg *a)
{
    HRESULT rc;
    Bstr bstrBaseFolder;
    Bstr bstrName;
    Bstr bstrOsTypeId;
    Bstr bstrUuid;
    bool fRegister = false;
    com::SafeArray<BSTR> groups;

    int c;
    RTGETOPTUNION ValueUnion;
    RTGETOPTSTATE GetState;
    // start at 0 because main() has hacked both the argc and argv given to us
    RTGetOptInit(&GetState, a->argc, a->argv, g_aCreateVMOptions, RT_ELEMENTS(g_aCreateVMOptions),
                 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
    while ((c = RTGetOpt(&GetState, &ValueUnion)))
    {
        switch (c)
        {
            case 'n':   // --name
                bstrName = ValueUnion.psz;
                break;

            case 'g':   // --groups
                parseGroups(ValueUnion.psz, &groups);
                break;

            case 'p':   // --basefolder
                bstrBaseFolder = ValueUnion.psz;
                break;

            case 'o':   // --ostype
                bstrOsTypeId = ValueUnion.psz;
                break;

            case 'u':   // --uuid
                bstrUuid = Guid(ValueUnion.Uuid).toUtf16().raw();
                break;

            case 'r':   // --register
                fRegister = true;
                break;

            default:
                return errorGetOpt(USAGE_CREATEVM, c, &ValueUnion);
        }
    }

    /* check for required options */
    if (bstrName.isEmpty())
        return errorSyntax(USAGE_CREATEVM, "Parameter --name is required");

    do
    {
        Bstr createFlags;
        if (!bstrUuid.isEmpty())
            createFlags = BstrFmt("UUID=%ls", bstrUuid.raw());
        Bstr bstrPrimaryGroup;
        if (groups.size())
            bstrPrimaryGroup = groups[0];
        Bstr bstrSettingsFile;
        CHECK_ERROR_BREAK(a->virtualBox,
                          ComposeMachineFilename(bstrName.raw(),
                                                 bstrPrimaryGroup.raw(),
                                                 createFlags.raw(),
                                                 bstrBaseFolder.raw(),
                                                 bstrSettingsFile.asOutParam()));
        ComPtr<IMachine> machine;
        CHECK_ERROR_BREAK(a->virtualBox,
                          CreateMachine(bstrSettingsFile.raw(),
                                        bstrName.raw(),
                                        ComSafeArrayAsInParam(groups),
                                        bstrOsTypeId.raw(),
                                        createFlags.raw(),
                                        machine.asOutParam()));

        CHECK_ERROR_BREAK(machine, SaveSettings());
        if (fRegister)
        {
            CHECK_ERROR_BREAK(a->virtualBox, RegisterMachine(machine));
        }
        Bstr uuid;
        CHECK_ERROR_BREAK(machine, COMGETTER(Id)(uuid.asOutParam()));
        Bstr settingsFile;
        CHECK_ERROR_BREAK(machine, COMGETTER(SettingsFilePath)(settingsFile.asOutParam()));
        RTPrintf("Virtual machine '%ls' is created%s.\n"
                 "UUID: %s\n"
                 "Settings file: '%ls'\n",
                 bstrName.raw(), fRegister ? " and registered" : "",
                 Utf8Str(uuid).c_str(), settingsFile.raw());
    }
    while (0);

    return SUCCEEDED(rc) ? 0 : 1;
}
HRESULT showMediumInfo(const ComPtr<IVirtualBox> &pVirtualBox,
                       const ComPtr<IMedium> &pMedium,
                       const char *pszParentUUID,
                       bool fOptLong)
{
    HRESULT rc = S_OK;
    do
    {
        Bstr uuid;
        pMedium->COMGETTER(Id)(uuid.asOutParam());
        RTPrintf("UUID:           %ls\n", uuid.raw());
        if (pszParentUUID)
            RTPrintf("Parent UUID:    %s\n", pszParentUUID);

        /* check for accessibility */
        MediumState_T enmState;
        CHECK_ERROR_BREAK(pMedium, RefreshState(&enmState));
        pMedium->RefreshState(&enmState);
        const char *pszState = "unknown";
        switch (enmState)
        {
            case MediumState_NotCreated:
                pszState = "not created";
                break;
            case MediumState_Created:
                pszState = "created";
                break;
            case MediumState_LockedRead:
                pszState = "locked read";
                break;
            case MediumState_LockedWrite:
                pszState = "locked write";
                break;
            case MediumState_Inaccessible:
                pszState = "inaccessible";
                break;
            case MediumState_Creating:
                pszState = "creating";
                break;
            case MediumState_Deleting:
                pszState = "deleting";
                break;
        }
        RTPrintf("State:          %s\n", pszState);

        if (fOptLong && enmState == MediumState_Inaccessible)
        {
            Bstr err;
            CHECK_ERROR_BREAK(pMedium, COMGETTER(LastAccessError)(err.asOutParam()));
            RTPrintf("Access Error:   %ls\n", err.raw());
        }

        if (fOptLong)
        {
            Bstr description;
            pMedium->COMGETTER(Description)(description.asOutParam());
            if (!description.isEmpty())
                RTPrintf("Description:    %ls\n", description.raw());
        }

        MediumType_T type;
        pMedium->COMGETTER(Type)(&type);
        const char *typeStr = "unknown";
        switch (type)
        {
            case MediumType_Normal:
                if (pszParentUUID && Guid(pszParentUUID).isValid())
                    typeStr = "normal (differencing)";
                else
                    typeStr = "normal (base)";
                break;
            case MediumType_Immutable:
                typeStr = "immutable";
                break;
            case MediumType_Writethrough:
                typeStr = "writethrough";
                break;
            case MediumType_Shareable:
                typeStr = "shareable";
                break;
            case MediumType_Readonly:
                typeStr = "readonly";
                break;
            case MediumType_MultiAttach:
                typeStr = "multiattach";
                break;
        }
        RTPrintf("Type:           %s\n", typeStr);

        /* print out information specific for differencing hard disks */
        if (fOptLong && pszParentUUID && Guid(pszParentUUID).isValid())
        {
            BOOL autoReset = FALSE;
            pMedium->COMGETTER(AutoReset)(&autoReset);
            RTPrintf("Auto-Reset:     %s\n", autoReset ? "on" : "off");
        }

        Bstr loc;
        pMedium->COMGETTER(Location)(loc.asOutParam());
        RTPrintf("Location:       %ls\n", loc.raw());

        Bstr format;
        pMedium->COMGETTER(Format)(format.asOutParam());
        RTPrintf("Storage format: %ls\n", format.raw());

        if (fOptLong)
        {
            com::SafeArray<MediumVariant_T> safeArray_variant;

            pMedium->COMGETTER(Variant)(ComSafeArrayAsOutParam(safeArray_variant));
            ULONG variant=0;
            for (size_t i = 0; i < safeArray_variant.size(); i++)
                variant |= safeArray_variant[i];

            const char *variantStr = "unknown";
            switch (variant & ~(MediumVariant_Fixed | MediumVariant_Diff))
            {
                case MediumVariant_VmdkSplit2G:
                    variantStr = "split2G";
                    break;
                case MediumVariant_VmdkStreamOptimized:
                    variantStr = "streamOptimized";
                    break;
                case MediumVariant_VmdkESX:
                    variantStr = "ESX";
                    break;
                case MediumVariant_Standard:
                    variantStr = "default";
                    break;
            }
            const char *variantTypeStr = "dynamic";
            if (variant & MediumVariant_Fixed)
                variantTypeStr = "fixed";
            else if (variant & MediumVariant_Diff)
                variantTypeStr = "differencing";
            RTPrintf("Format variant: %s %s\n", variantTypeStr, variantStr);
        }

        LONG64 logicalSize;
        pMedium->COMGETTER(LogicalSize)(&logicalSize);
        RTPrintf("Capacity:       %lld MBytes\n", logicalSize >> 20);
        if (fOptLong)
        {
            LONG64 actualSize;
            pMedium->COMGETTER(Size)(&actualSize);
            RTPrintf("Size on disk:   %lld MBytes\n", actualSize >> 20);
        }

        if (fOptLong)
        {
            com::SafeArray<BSTR> names;
            com::SafeArray<BSTR> values;
            pMedium->GetProperties(Bstr().raw(), ComSafeArrayAsOutParam(names), ComSafeArrayAsOutParam(values));
            size_t cNames = names.size();
            size_t cValues = values.size();
            bool fFirst = true;
            for (size_t i = 0; i < cNames; i++)
            {
                Bstr value;
                if (i < cValues)
                    value = values[i];
                RTPrintf("%s%ls=%ls\n",
                         fFirst ? "Property:       " : "                ",
                         names[i], value.raw());
            }
        }

        if (fOptLong)
        {
            bool fFirst = true;
            com::SafeArray<BSTR> machineIds;
            pMedium->COMGETTER(MachineIds)(ComSafeArrayAsOutParam(machineIds));
            for (size_t i = 0; i < machineIds.size(); i++)
            {
                ComPtr<IMachine> machine;
                CHECK_ERROR(pVirtualBox, FindMachine(machineIds[i], machine.asOutParam()));
                if (machine)
                {
                    Bstr name;
                    machine->COMGETTER(Name)(name.asOutParam());
                    machine->COMGETTER(Id)(uuid.asOutParam());
                    RTPrintf("%s%ls (UUID: %ls)",
                             fFirst ? "In use by VMs:  " : "                ",
                             name.raw(), machineIds[i]);
                    fFirst = false;
                    com::SafeArray<BSTR> snapshotIds;
                    pMedium->GetSnapshotIds(machineIds[i],
                                            ComSafeArrayAsOutParam(snapshotIds));
                    for (size_t j = 0; j < snapshotIds.size(); j++)
                    {
                        ComPtr<ISnapshot> snapshot;
                        machine->FindSnapshot(snapshotIds[j], snapshot.asOutParam());
                        if (snapshot)
                        {
                            Bstr snapshotName;
                            snapshot->COMGETTER(Name)(snapshotName.asOutParam());
                            RTPrintf(" [%ls (UUID: %ls)]", snapshotName.raw(), snapshotIds[j]);
                        }
                    }
                    RTPrintf("\n");
                }
            }
        }

        if (fOptLong)
        {
            com::SafeIfaceArray<IMedium> children;
            pMedium->COMGETTER(Children)(ComSafeArrayAsOutParam(children));
            bool fFirst = true;
            for (size_t i = 0; i < children.size(); i++)
            {
                ComPtr<IMedium> pChild(children[i]);
                if (pChild)
                {
                    Bstr childUUID;
                    pChild->COMGETTER(Id)(childUUID.asOutParam());
                    RTPrintf("%s%ls\n",
                             fFirst ? "Child UUIDs:    " : "                ",
                             childUUID.raw());
                    fFirst = false;
                }
            }
        }
    }
    while (0);

    return rc;
}
Example #23
0
DECLEXPORT(AuthResult) AUTHCALL AuthEntry(const char *szCaller,
                                          PAUTHUUID pUuid,
                                          AuthGuestJudgement guestJudgement,
                                          const char *szUser,
                                          const char *szPassword,
                                          const char *szDomain,
                                          int fLogon,
                                          unsigned clientId)
{
    /* default is failed */
    AuthResult result = AuthResultAccessDenied;

    /* only interested in logon */
    if (!fLogon)
        /* return value ignored */
        return result;

    char uuid[RTUUID_STR_LENGTH] = {0};
    if (pUuid)
        RTUuidToStr((PCRTUUID)pUuid, (char*)uuid, RTUUID_STR_LENGTH);

    /* the user might contain a domain name, split it */
    char *user = strchr((char*)szUser, '\\');
    if (user)
        user++;
    else
        user = (char*)szUser;

    dprintf("VBoxAuth: uuid: %s, user: %s, szPassword: %s\n", uuid, user, szPassword);

    ComPtr<IVirtualBoxClient> virtualBoxClient;
    ComPtr<IVirtualBox> virtualBox;
    HRESULT rc;

    rc = virtualBoxClient.createInprocObject(CLSID_VirtualBoxClient);
    if (SUCCEEDED(rc))
        rc = virtualBoxClient->COMGETTER(VirtualBox)(virtualBox.asOutParam());
    if (SUCCEEDED(rc))
    {
        Bstr key = BstrFmt("VBoxAuthSimple/users/%s", user);
        Bstr password;

        /* lookup in VM's extra data? */
        if (pUuid)
        {
            ComPtr<IMachine> machine;
            virtualBox->FindMachine(Bstr(uuid).raw(), machine.asOutParam());
            if (machine)
                machine->GetExtraData(key.raw(), password.asOutParam());
        } else
            /* lookup global extra data */
            virtualBox->GetExtraData(key.raw(), password.asOutParam());

        if (!password.isEmpty())
        {
            /* calculate hash */
            uint8_t abDigest[RTSHA256_HASH_SIZE];
            RTSha256(szPassword, strlen(szPassword), abDigest);
            char pszDigest[RTSHA256_DIGEST_LEN + 1];
            RTSha256ToString(abDigest, pszDigest, sizeof(pszDigest));

            if (password == pszDigest)
                result = AuthResultAccessGranted;
        }
    }
    else
        dprintf("VBoxAuth: failed to get VirtualBox object reference: %Rhrc\n", rc);

    return result;
}
HRESULT VRDEServer::getVRDEProperties(std::vector<com::Utf8Str> &aProperties)
{
    size_t cProperties = 0;
    aProperties.resize(0);
    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);
    if (!mData->mEnabled)
    {
        return S_OK;
    }
    alock.release();

    /*
     * Check that a VRDE extension pack name is set and resolve it into a
     * library path.
     */
    Bstr bstrExtPack;
    HRESULT hrc = COMGETTER(VRDEExtPack)(bstrExtPack.asOutParam());
    Log(("VRDEPROP: get extpack hrc 0x%08X, isEmpty %d\n", hrc, bstrExtPack.isEmpty()));
    if (FAILED(hrc))
        return hrc;
    if (bstrExtPack.isEmpty())
        return E_FAIL;

    Utf8Str strExtPack(bstrExtPack);
    Utf8Str strVrdeLibrary;
    int vrc = VINF_SUCCESS;
    if (strExtPack.equals(VBOXVRDP_KLUDGE_EXTPACK_NAME))
        strVrdeLibrary = "VBoxVRDP";
    else
    {
#ifdef VBOX_WITH_EXTPACK
        VirtualBox *pVirtualBox = mParent->i_getVirtualBox();
        ExtPackManager *pExtPackMgr = pVirtualBox->i_getExtPackManager();
        vrc = pExtPackMgr->i_getVrdeLibraryPathForExtPack(&strExtPack, &strVrdeLibrary);
#else
        vrc = VERR_FILE_NOT_FOUND;
#endif
    }
    Log(("VRDEPROP: library get rc %Rrc\n", vrc));

    if (RT_SUCCESS(vrc))
    {
        /*
         * Load the VRDE library and start the server, if it is enabled.
         */
        PFNVRDESUPPORTEDPROPERTIES pfn = NULL;
        RTLDRMOD hmod = NIL_RTLDRMOD;
        vrc = loadVRDELibrary(strVrdeLibrary.c_str(), &hmod, &pfn);
        Log(("VRDEPROP: load library [%s] rc %Rrc\n", strVrdeLibrary.c_str(), vrc));
        if (RT_SUCCESS(vrc))
        {
            const char * const *papszNames = pfn();

            if (papszNames)
            {
                size_t i;
                for (i = 0; papszNames[i] != NULL; ++i)
                {
                    cProperties++;
                }
            }
            Log(("VRDEPROP: %d properties\n", cProperties));

            if (cProperties > 0)
            {
                aProperties.resize(cProperties);
                for (size_t i = 0; papszNames[i] != NULL && i < cProperties; ++i)
                {
                     aProperties[i] = papszNames[i];
                }
            }

            /* Do not forget to unload the library. */
            RTLdrClose(hmod);
            hmod = NIL_RTLDRMOD;
        }
    }

    if (RT_FAILURE(vrc))
    {
        return E_FAIL;
    }

    return S_OK;
}
/**
 *  Returns true if the given USB device matches to at least one of
 *  this controller's USB device filters.
 *
 *  A generic version that accepts any IUSBDevice on input.
 *
 *  @note
 *      This method MUST correlate with HostUSBDevice::isMatch()
 *      in the sense of the device matching logic.
 *
 *  @note Locks this object for reading.
 */
bool USBController::hasMatchingFilter (IUSBDevice *aUSBDevice, ULONG *aMaskedIfs)
{
    LogFlowThisFuncEnter();

    AutoCaller autoCaller(this);
    AssertComRCReturn (autoCaller.rc(), false);

    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);

    /* Disabled USB controllers cannot actually work with USB devices */
    if (!m->bd->fEnabled)
        return false;

    HRESULT rc = S_OK;

    /* query fields */
    USBFILTER dev;
    USBFilterInit (&dev, USBFILTERTYPE_CAPTURE);

    USHORT vendorId = 0;
    rc = aUSBDevice->COMGETTER(VendorId) (&vendorId);
    ComAssertComRCRet(rc, false);
    ComAssertRet(vendorId, false);
    int vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_VENDOR_ID, vendorId, true); AssertRC(vrc);

    USHORT productId = 0;
    rc = aUSBDevice->COMGETTER(ProductId) (&productId);
    ComAssertComRCRet(rc, false);
    vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_PRODUCT_ID, productId, true); AssertRC(vrc);

    USHORT revision;
    rc = aUSBDevice->COMGETTER(Revision) (&revision);
    ComAssertComRCRet(rc, false);
    vrc = USBFilterSetNumExact (&dev, USBFILTERIDX_DEVICE, revision, true); AssertRC(vrc);

    Bstr manufacturer;
    rc = aUSBDevice->COMGETTER(Manufacturer) (manufacturer.asOutParam());
    ComAssertComRCRet(rc, false);
    if (!manufacturer.isEmpty())
        USBFilterSetStringExact (&dev, USBFILTERIDX_MANUFACTURER_STR, Utf8Str(manufacturer).c_str(), true);

    Bstr product;
    rc = aUSBDevice->COMGETTER(Product) (product.asOutParam());
    ComAssertComRCRet(rc, false);
    if (!product.isEmpty())
        USBFilterSetStringExact (&dev, USBFILTERIDX_PRODUCT_STR, Utf8Str(product).c_str(), true);

    Bstr serialNumber;
    rc = aUSBDevice->COMGETTER(SerialNumber) (serialNumber.asOutParam());
    ComAssertComRCRet(rc, false);
    if (!serialNumber.isEmpty())
        USBFilterSetStringExact (&dev, USBFILTERIDX_SERIAL_NUMBER_STR, Utf8Str(serialNumber).c_str(), true);

    Bstr address;
    rc = aUSBDevice->COMGETTER(Address) (address.asOutParam());
    ComAssertComRCRet(rc, false);

    USHORT port = 0;
    rc = aUSBDevice->COMGETTER(Port)(&port);
    ComAssertComRCRet(rc, false);
    USBFilterSetNumExact (&dev, USBFILTERIDX_PORT, port, true);

    BOOL remote = FALSE;
    rc = aUSBDevice->COMGETTER(Remote)(&remote);
    ComAssertComRCRet(rc, false);
    ComAssertRet(remote == TRUE, false);

    bool match = false;

    /* apply self filters */
    for (DeviceFilterList::const_iterator it = m->llDeviceFilters->begin();
         it != m->llDeviceFilters->end();
         ++ it)
    {
        AutoWriteLock filterLock(*it COMMA_LOCKVAL_SRC_POS);
        const USBDeviceFilter::Data &aData = (*it)->getData();

        if (!aData.mActive)
            continue;
        if (!aData.mRemote.isMatch (remote))
            continue;
        if (!USBFilterMatch (&aData.mUSBFilter, &dev))
            continue;

        match = true;
        *aMaskedIfs = aData.mMaskedIfs;
        break;
    }

    LogFlowThisFunc(("returns: %d\n", match));
    LogFlowThisFuncLeave();

    return match;
}
HRESULT Guest::taskUpdateGuestAdditions(GuestTask *aTask)
{
    LogFlowFuncEnter();

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    /*
     * Do *not* take a write lock here since we don't (and won't)
     * touch any class-specific data (of IGuest) here - only the member functions
     * which get called here can do that.
     */

    HRESULT rc = S_OK;
    BOOL fCompleted;
    BOOL fCanceled;

    try
    {
        ComObjPtr<Guest> pGuest = aTask->pGuest;

        aTask->pProgress->SetCurrentOperationProgress(10);

        /*
         * Determine guest OS type and the required installer image.
         * At the moment only Windows guests are supported.
         */
        Utf8Str installerImage;
        Bstr osTypeId;
        if (   SUCCEEDED(pGuest->COMGETTER(OSTypeId(osTypeId.asOutParam())))
            && !osTypeId.isEmpty())
        {
            Utf8Str osTypeIdUtf8(osTypeId); /* Needed for .contains(). */
            if (   osTypeIdUtf8.contains("Microsoft", Utf8Str::CaseInsensitive)
                || osTypeIdUtf8.contains("Windows", Utf8Str::CaseInsensitive))
            {
                if (osTypeIdUtf8.contains("64", Utf8Str::CaseInsensitive))
                    installerImage = "VBOXWINDOWSADDITIONS_AMD64.EXE";
                else
                    installerImage = "VBOXWINDOWSADDITIONS_X86.EXE";
                /* Since the installers are located in the root directory,
                 * no further path processing needs to be done (yet). */
            }
            else /* Everything else is not supported (yet). */
                throw GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->pProgress,
                                                      Guest::tr("Detected guest OS (%s) does not support automatic Guest Additions updating, please update manually"),
                                                      osTypeIdUtf8.c_str());
        }
        else
            throw GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->pProgress,
                                                  Guest::tr("Could not detected guest OS type/version, please update manually"));
        Assert(!installerImage.isEmpty());

        /*
         * Try to open the .ISO file and locate the specified installer.
         */
        RTISOFSFILE iso;
        int vrc = RTIsoFsOpen(&iso, aTask->strSource.c_str());
        if (RT_FAILURE(vrc))
        {
            rc = GuestTask::setProgressErrorInfo(VBOX_E_FILE_ERROR, aTask->pProgress,
                                                 Guest::tr("Invalid installation medium detected: \"%s\""),
                                                 aTask->strSource.c_str());
        }
        else
        {
            uint32_t cbOffset;
            size_t cbLength;
            vrc = RTIsoFsGetFileInfo(&iso, installerImage.c_str(), &cbOffset, &cbLength);
            if (   RT_SUCCESS(vrc)
                && cbOffset
                && cbLength)
            {
                vrc = RTFileSeek(iso.file, cbOffset, RTFILE_SEEK_BEGIN, NULL);
                if (RT_FAILURE(vrc))
                    rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress,
                                                         Guest::tr("Could not seek to setup file on installation medium \"%s\" (%Rrc)"),
                                                         aTask->strSource.c_str(), vrc);
            }
            else
            {
                switch (vrc)
                {
                    case VERR_FILE_NOT_FOUND:
                        rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress,
                                                             Guest::tr("Setup file was not found on installation medium \"%s\""),
                                                             aTask->strSource.c_str());
                        break;

                    default:
                        rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress,
                                                             Guest::tr("An unknown error (%Rrc) occured while retrieving information of setup file on installation medium \"%s\""),
                                                             vrc, aTask->strSource.c_str());
                        break;
                }
            }

            /* Specify the ouput path on the guest side. */
            Utf8Str strInstallerPath = "%TEMP%\\VBoxWindowsAdditions.exe";

            if (RT_SUCCESS(vrc))
            {
                /* Okay, we're ready to start our copy routine on the guest! */
                aTask->pProgress->SetCurrentOperationProgress(15);

                /* Prepare command line args. */
                com::SafeArray<IN_BSTR> args;
                com::SafeArray<IN_BSTR> env;

                args.push_back(Bstr("--output").raw());               /* We want to write a file ... */
                args.push_back(Bstr(strInstallerPath.c_str()).raw()); /* ... with this path. */

                if (SUCCEEDED(rc))
                {
                    ComPtr<IProgress> progressCat;
                    ULONG uPID;

                    /*
                     * Start built-in "vbox_cat" tool (inside VBoxService) to
                     * copy over/pipe the data into a file on the guest (with
                     * system rights, no username/password specified).
                     */
                    rc = pGuest->executeProcessInternal(Bstr(VBOXSERVICE_TOOL_CAT).raw(),
                                                          ExecuteProcessFlag_Hidden
                                                        | ExecuteProcessFlag_WaitForProcessStartOnly,
                                                        ComSafeArrayAsInParam(args),
                                                        ComSafeArrayAsInParam(env),
                                                        Bstr("").raw() /* Username. */,
                                                        Bstr("").raw() /* Password */,
                                                        5 * 1000 /* Wait 5s for getting the process started. */,
                                                        &uPID, progressCat.asOutParam(), &vrc);
                    if (FAILED(rc))
                    {
                        /* Errors which return VBOX_E_NOT_SUPPORTED can be safely skipped by the caller
                         * to silently fall back to "normal" (old) .ISO mounting. */

                        /* Due to a very limited COM error range we use vrc for a more detailed error
                         * lookup to figure out what went wrong. */
                        switch (vrc)
                        {
                            /* Guest execution service is not (yet) ready. This basically means that either VBoxService
                             * is not running (yet) or that the Guest Additions are too old (because VBoxService does not
                             * support the guest execution feature in this version). */
                            case VERR_NOT_FOUND:
                                LogRel(("Guest Additions seem not to be installed yet\n"));
                                rc = GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->pProgress,
                                                                     Guest::tr("Guest Additions seem not to be installed or are not ready to update yet"));
                                break;

                            /* Getting back a VERR_INVALID_PARAMETER indicates that the installed Guest Additions are supporting the guest
                             * execution but not the built-in "vbox_cat" tool of VBoxService (< 4.0). */
                            case VERR_INVALID_PARAMETER:
                                LogRel(("Guest Additions are installed but don't supported automatic updating\n"));
                                rc = GuestTask::setProgressErrorInfo(VBOX_E_NOT_SUPPORTED, aTask->pProgress,
                                                                     Guest::tr("Installed Guest Additions do not support automatic updating"));
                                break;

                            case VERR_TIMEOUT:
                                LogRel(("Guest was unable to start copying the Guest Additions setup within time\n"));
                                rc = GuestTask::setProgressErrorInfo(E_FAIL, aTask->pProgress,
                                                                     Guest::tr("Guest was unable to start copying the Guest Additions setup within time"));
                                break;

                            default:
                                rc = GuestTask::setProgressErrorInfo(E_FAIL, aTask->pProgress,
                                                                     Guest::tr("Error copying Guest Additions setup file to guest path \"%s\" (%Rrc)"),
                                                                     strInstallerPath.c_str(), vrc);
                                break;
                        }
                    }
                    else
                    {
                        LogRel(("Automatic update of Guest Additions started, using \"%s\"\n", aTask->strSource.c_str()));
                        LogRel(("Copying Guest Additions installer \"%s\" to \"%s\" on guest ...\n",
                                installerImage.c_str(), strInstallerPath.c_str()));
                        aTask->pProgress->SetCurrentOperationProgress(20);

                        /* Wait for process to exit ... */
                        SafeArray<BYTE> aInputData(_64K);
                        while (   SUCCEEDED(progressCat->COMGETTER(Completed(&fCompleted)))
                               && !fCompleted)
                        {
                            size_t cbRead;
                            /* cbLength contains remaining bytes of our installer file
                             * opened above to read. */
                            size_t cbToRead = RT_MIN(cbLength, _64K);
                            if (cbToRead)
                            {
                                vrc = RTFileRead(iso.file, (uint8_t*)aInputData.raw(), cbToRead, &cbRead);
                                if (   cbRead
                                    && RT_SUCCESS(vrc))
                                {
                                    /* Resize buffer to reflect amount we just have read. */
                                    if (cbRead > 0)
                                        aInputData.resize(cbRead);

                                    /* Did we reach the end of the content we want to transfer (last chunk)? */
                                    ULONG uFlags = ProcessInputFlag_None;
                                    if (   (cbRead < _64K)
                                        /* Did we reach the last block which is exactly _64K? */
                                        || (cbToRead - cbRead == 0)
                                        /* ... or does the user want to cancel? */
                                        || (   SUCCEEDED(aTask->pProgress->COMGETTER(Canceled(&fCanceled)))
                                            && fCanceled)
                                       )
                                    {
                                        uFlags |= ProcessInputFlag_EndOfFile;
                                    }

                                    /* Transfer the current chunk ... */
                                #ifdef DEBUG_andy
                                    LogRel(("Copying Guest Additions (%u bytes left) ...\n", cbLength));
                                #endif
                                    ULONG uBytesWritten;
                                    rc = pGuest->SetProcessInput(uPID, uFlags,
                                                                 10 * 1000 /* Wait 10s for getting the input data transfered. */,
                                                                 ComSafeArrayAsInParam(aInputData), &uBytesWritten);
                                    if (FAILED(rc))
                                    {
                                        rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest);
                                        break;
                                    }

                                    /* If task was canceled above also cancel the process execution. */
                                    if (fCanceled)
                                        progressCat->Cancel();

                                #ifdef DEBUG_andy
                                    LogRel(("Copying Guest Additions (%u bytes written) ...\n", uBytesWritten));
                                #endif
                                    Assert(cbLength >= uBytesWritten);
                                    cbLength -= uBytesWritten;
                                }
                                else if (RT_FAILURE(vrc))
                                {
                                    rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress,
                                                                         Guest::tr("Error while reading setup file \"%s\" (To read: %u, Size: %u) from installation medium (%Rrc)"),
                                                                         installerImage.c_str(), cbToRead, cbLength, vrc);
                                }
                            }

                            /* Internal progress canceled? */
                            if (   SUCCEEDED(progressCat->COMGETTER(Canceled(&fCanceled)))
                                && fCanceled)
                            {
                                aTask->pProgress->Cancel();
                                break;
                            }
                        }
                    }
                }
            }
            RTIsoFsClose(&iso);

            if (   SUCCEEDED(rc)
                && (   SUCCEEDED(aTask->pProgress->COMGETTER(Canceled(&fCanceled)))
                    && !fCanceled
                   )
               )
            {
                /*
                 * Installer was transferred successfully, so let's start it
                 * (with system rights).
                 */
                LogRel(("Preparing to execute Guest Additions update ...\n"));
                aTask->pProgress->SetCurrentOperationProgress(66);

                /* Prepare command line args for installer. */
                com::SafeArray<IN_BSTR> installerArgs;
                com::SafeArray<IN_BSTR> installerEnv;

                /** @todo Only Windows! */
                installerArgs.push_back(Bstr(strInstallerPath).raw()); /* The actual (internal) installer image (as argv[0]). */
                /* Note that starting at Windows Vista the lovely session 0 separation applies:
                 * This means that if we run an application with the profile/security context
                 * of VBoxService (system rights!) we're not able to show any UI. */
                installerArgs.push_back(Bstr("/S").raw());      /* We want to install in silent mode. */
                installerArgs.push_back(Bstr("/l").raw());      /* ... and logging enabled. */
                /* Don't quit VBoxService during upgrade because it still is used for this
                 * piece of code we're in right now (that is, here!) ... */
                installerArgs.push_back(Bstr("/no_vboxservice_exit").raw());
                /* Tell the installer to report its current installation status
                 * using a running VBoxTray instance via balloon messages in the
                 * Windows taskbar. */
                installerArgs.push_back(Bstr("/post_installstatus").raw());

                /*
                 * Start the just copied over installer with system rights
                 * in silent mode on the guest. Don't use the hidden flag since there
                 * may be pop ups the user has to process.
                 */
                ComPtr<IProgress> progressInstaller;
                ULONG uPID;
                rc = pGuest->executeProcessInternal(Bstr(strInstallerPath).raw(),
                                                    ExecuteProcessFlag_WaitForProcessStartOnly,
                                                    ComSafeArrayAsInParam(installerArgs),
                                                    ComSafeArrayAsInParam(installerEnv),
                                                    Bstr("").raw() /* Username */,
                                                    Bstr("").raw() /* Password */,
                                                    10 * 1000 /* Wait 10s for getting the process started */,
                                                    &uPID, progressInstaller.asOutParam(), &vrc);
                if (SUCCEEDED(rc))
                {
                    LogRel(("Guest Additions update is running ...\n"));

                    /* If the caller does not want to wait for out guest update process to end,
                     * complete the progress object now so that the caller can do other work. */
                    if (aTask->uFlags & AdditionsUpdateFlag_WaitForUpdateStartOnly)
                        aTask->pProgress->notifyComplete(S_OK);
                    else
                        aTask->pProgress->SetCurrentOperationProgress(70);

                    /* Wait until the Guest Additions installer finishes ... */
                    while (   SUCCEEDED(progressInstaller->COMGETTER(Completed(&fCompleted)))
                           && !fCompleted)
                    {
                        if (   SUCCEEDED(aTask->pProgress->COMGETTER(Canceled(&fCanceled)))
                            && fCanceled)
                        {
                            progressInstaller->Cancel();
                            break;
                        }
                        /* Progress canceled by Main API? */
                        if (   SUCCEEDED(progressInstaller->COMGETTER(Canceled(&fCanceled)))
                            && fCanceled)
                        {
                            break;
                        }
                        RTThreadSleep(100);
                    }

                    ExecuteProcessStatus_T retStatus;
                    ULONG uRetExitCode, uRetFlags;
                    rc = pGuest->GetProcessStatus(uPID, &uRetExitCode, &uRetFlags, &retStatus);
                    if (SUCCEEDED(rc))
                    {
                        if (fCompleted)
                        {
                            if (uRetExitCode == 0)
                            {
                                LogRel(("Guest Additions update successful!\n"));
                                if (   SUCCEEDED(aTask->pProgress->COMGETTER(Completed(&fCompleted)))
                                    && !fCompleted)
                                    aTask->pProgress->notifyComplete(S_OK);
                            }
                            else
                            {
                                LogRel(("Guest Additions update failed (Exit code=%u, Status=%u, Flags=%u)\n",
                                        uRetExitCode, retStatus, uRetFlags));
                                rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress,
                                                                     Guest::tr("Guest Additions update failed with exit code=%u (status=%u, flags=%u)"),
                                                                     uRetExitCode, retStatus, uRetFlags);
                            }
                        }
                        else if (   SUCCEEDED(progressInstaller->COMGETTER(Canceled(&fCanceled)))
                                 && fCanceled)
                        {
                            LogRel(("Guest Additions update was canceled\n"));
                            rc = GuestTask::setProgressErrorInfo(VBOX_E_IPRT_ERROR, aTask->pProgress,
                                                                 Guest::tr("Guest Additions update was canceled by the guest with exit code=%u (status=%u, flags=%u)"),
                                                                 uRetExitCode, retStatus, uRetFlags);
                        }
                        else
                        {
                            LogRel(("Guest Additions update was canceled by the user\n"));
                        }
                    }
                    else
                        rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest);
                }
                else
                    rc = GuestTask::setProgressErrorInfo(rc, aTask->pProgress, pGuest);
            }
        }
    }
    catch (HRESULT aRC)
    {
        rc = aRC;
    }

    /* Clean up */
    aTask->rc = rc;

    LogFlowFunc(("rc=%Rhrc\n", rc));
    LogFlowFuncLeave();

    return VINF_SUCCESS;
}
Example #27
0
STDMETHODIMP Guest::COMGETTER(AdditionsVersion) (BSTR *aAdditionsVersion)
{
    CheckComArgOutPointerValid(aAdditionsVersion);

    AutoCaller autoCaller(this);
    if (FAILED(autoCaller.rc())) return autoCaller.rc();

    AutoReadLock alock(this COMMA_LOCKVAL_SRC_POS);

    HRESULT hr = S_OK;
    if (   mData.mAdditionsVersion.isEmpty()
        /* Only try alternative way if GA are active! */
        && mData.mAdditionsRunLevel > AdditionsRunLevelType_None)
    {
        /*
         * If we got back an empty string from GetAdditionsVersion() we either
         * really don't have the Guest Additions version yet or the guest is running
         * older Guest Additions (< 3.2.0) which don't provide VMMDevReq_ReportGuestInfo2,
         * so get the version + revision from the (hopefully) provided guest properties
         * instead.
         */
        Bstr addVersion;
        LONG64 u64Timestamp;
        Bstr flags;
        hr = mParent->machine()->GetGuestProperty(Bstr("/VirtualBox/GuestAdd/Version").raw(),
                                                  addVersion.asOutParam(), &u64Timestamp, flags.asOutParam());
        if (hr == S_OK)
        {
            Bstr addRevision;
            hr = mParent->machine()->GetGuestProperty(Bstr("/VirtualBox/GuestAdd/Revision").raw(),
                                                      addRevision.asOutParam(), &u64Timestamp, flags.asOutParam());
            if (   hr == S_OK
                && !addVersion.isEmpty()
                && !addRevision.isEmpty())
            {
                /* Some Guest Additions versions had interchanged version + revision values,
                 * so check if the version value at least has a dot to identify it and change
                 * both values to reflect the right content. */
                if (!Utf8Str(addVersion).contains("."))
                {
                    Bstr addTemp = addVersion;
                    addVersion = addRevision;
                    addRevision = addTemp;
                }

                Bstr additionsVersion = BstrFmt("%ls r%ls",
                                                addVersion.raw(), addRevision.raw());
                additionsVersion.cloneTo(aAdditionsVersion);
            }
            /** @todo r=bird: else: Should not return failure! */
        }
        else
        {
            /* If getting the version + revision above fails or they simply aren't there
             * because of *really* old Guest Additions we only can report the interface
             * version to at least have something. */
            mData.mInterfaceVersion.cloneTo(aAdditionsVersion);
            /** @todo r=bird: hr is still indicating failure! */
        }
    }
    else
        mData.mAdditionsVersion.cloneTo(aAdditionsVersion);

    return hr;
}
void HostPowerService::notify(Reason_T aReason)
{
    SessionMachinesList machines;
    VirtualBox::InternalControlList controls;

    HRESULT rc = S_OK;

    switch (aReason)
    {
        case Reason_HostSuspend:
        {
            LogFunc(("HOST SUSPEND\n"));

#ifdef VBOX_WITH_RESOURCE_USAGE_API
            /* Suspend performance sampling to avoid unnecessary callbacks due to jumps in time. */
            PerformanceCollector *perfcollector = mVirtualBox->i_performanceCollector();

            if (perfcollector)
                perfcollector->suspendSampling();
#endif
            mVirtualBox->i_getOpenedMachines(machines, &controls);

            /* pause running VMs */
            for (VirtualBox::InternalControlList::const_iterator it = controls.begin();
                 it != controls.end();
                 ++it)
            {
                ComPtr<IInternalSessionControl> pControl = *it;

                /* PauseWithReason() will simply return a failure if
                 * the VM is in an inappropriate state */
                rc = pControl->PauseWithReason(Reason_HostSuspend);
                if (FAILED(rc))
                    continue;

                /* save the control to un-pause the VM later */
                mSessionControls.push_back(pControl);
            }

            LogRel(("Host suspending: Paused %d VMs\n", mSessionControls.size()));
            break;
        }

        case Reason_HostResume:
        {
            LogFunc(("HOST RESUME\n"));

            size_t resumed = 0;

            /* go through VMs we paused on Suspend */
            for (size_t i = 0; i < mSessionControls.size(); ++i)
            {
                /* note that Resume() will simply return a failure if the VM is
                 * in an inappropriate state (it will also fail if the VM has
                 * been somehow closed by this time already so that the
                 * console reference we have is dead) */
                rc = mSessionControls[i]->ResumeWithReason(Reason_HostResume);
                if (FAILED(rc))
                    continue;

                ++resumed;
            }

            LogRel(("Host resumed: Resumed %d VMs\n", resumed));

#ifdef VBOX_WITH_RESOURCE_USAGE_API
            /* Resume the performance sampling. */
            PerformanceCollector *perfcollector = mVirtualBox->i_performanceCollector();

            if (perfcollector)
                perfcollector->resumeSampling();
#endif

            mSessionControls.clear();
            break;
        }

        case Reason_HostBatteryLow:
        {
            LogFunc(("BATTERY LOW\n"));

            Bstr value;
            rc = mVirtualBox->GetExtraData(Bstr("VBoxInternal2/SavestateOnBatteryLow").raw(),
                                           value.asOutParam());
            int fGlobal = 0;
            if (SUCCEEDED(rc) && !value.isEmpty())
            {
                if (value != "0")
                    fGlobal = 1;
                else if (value == "0")
                    fGlobal = -1;
            }

            mVirtualBox->i_getOpenedMachines(machines, &controls);
            size_t saved = 0;

            /* save running VMs */
            for (SessionMachinesList::const_iterator it = machines.begin();
                 it != machines.end();
                 ++it)
            {
                ComPtr<SessionMachine> pMachine = *it;
                rc = pMachine->GetExtraData(Bstr("VBoxInternal2/SavestateOnBatteryLow").raw(),
                                            value.asOutParam());
                int fPerVM = 0;
                if (SUCCEEDED(rc) && !value.isEmpty())
                {
                    /* per-VM overrides global */
                    if (value != "0")
                        fPerVM = 2;
                    else if (value == "0")
                        fPerVM = -2;
                }

                /* default is true */
                if (fGlobal + fPerVM >= 0)
                {
                    ComPtr<IProgress> progress;

                    /* SessionMachine::i_saveStateWithReason() will return
                     * a failure if the VM is in an inappropriate state */
                    rc = pMachine->i_saveStateWithReason(Reason_HostBatteryLow, progress);
                    if (FAILED(rc))
                    {
                        LogRel(("SaveState '%s' failed with %Rhrc\n", pMachine->i_getName().c_str(), rc));
                        continue;
                    }

                    /* Wait until the operation has been completed. */
                    rc = progress->WaitForCompletion(-1);
                    if (SUCCEEDED(rc))
                    {
                        LONG iRc;
                        progress->COMGETTER(ResultCode)(&iRc);
                        rc = iRc;
                    }

                    AssertMsg(SUCCEEDED(rc), ("SaveState WaitForCompletion failed with %Rhrc (%#08X)\n", rc, rc));

                    if (SUCCEEDED(rc))
                    {
                        LogRel(("SaveState '%s' succeeded\n", pMachine->i_getName().c_str()));
                        ++saved;
                    }
                }
            }
            LogRel(("Battery Low: saved %d VMs\n", saved));
            break;
        }

        default:
            /* nothing */;
    }
}
int handleCloneHardDisk(HandlerArg *a)
{
    HRESULT rc;
    int vrc;
    const char *pszSrc = NULL;
    const char *pszDst = NULL;
    Bstr format;
    MediumVariant_T DiskVariant = MediumVariant_Standard;
    bool fExisting = false;

    int c;
    RTGETOPTUNION ValueUnion;
    RTGETOPTSTATE GetState;
    // start at 0 because main() has hacked both the argc and argv given to us
    RTGetOptInit(&GetState, a->argc, a->argv, g_aCloneHardDiskOptions, RT_ELEMENTS(g_aCloneHardDiskOptions),
                 0, RTGETOPTINIT_FLAGS_NO_STD_OPTS);
    while ((c = RTGetOpt(&GetState, &ValueUnion)))
    {
        switch (c)
        {
            case 'o':   // --format
                format = ValueUnion.psz;
                break;

            case 'F':   // --static
            {
                unsigned uDiskVariant = (unsigned)DiskVariant;
                uDiskVariant |= MediumVariant_Fixed;
                DiskVariant = (MediumVariant_T)uDiskVariant;
                break;
            }

            case 'E':   // --existing
                fExisting = true;
                break;

            case 'm':   // --variant
                vrc = parseDiskVariant(ValueUnion.psz, &DiskVariant);
                if (RT_FAILURE(vrc))
                    return errorArgument("Invalid hard disk variant '%s'", ValueUnion.psz);
                break;

            case VINF_GETOPT_NOT_OPTION:
                if (!pszSrc)
                    pszSrc = ValueUnion.psz;
                else if (!pszDst)
                    pszDst = ValueUnion.psz;
                else
                    return errorSyntax(USAGE_CLONEHD, "Invalid parameter '%s'", ValueUnion.psz);
                break;

            default:
                if (c > 0)
                {
                    if (RT_C_IS_GRAPH(c))
                        return errorSyntax(USAGE_CLONEHD, "unhandled option: -%c", c);
                    else
                        return errorSyntax(USAGE_CLONEHD, "unhandled option: %i", c);
                }
                else if (c == VERR_GETOPT_UNKNOWN_OPTION)
                    return errorSyntax(USAGE_CLONEHD, "unknown option: %s", ValueUnion.psz);
                else if (ValueUnion.pDef)
                    return errorSyntax(USAGE_CLONEHD, "%s: %Rrs", ValueUnion.pDef->pszLong, c);
                else
                    return errorSyntax(USAGE_CLONEHD, "error: %Rrs", c);
        }
    }

    if (!pszSrc)
        return errorSyntax(USAGE_CLONEHD, "Mandatory UUID or input file parameter missing");
    if (!pszDst)
        return errorSyntax(USAGE_CLONEHD, "Mandatory output file parameter missing");
    if (fExisting && (!format.isEmpty() || DiskVariant != MediumType_Normal))
        return errorSyntax(USAGE_CLONEHD, "Specified options which cannot be used with --existing");

    ComPtr<IMedium> srcDisk;
    ComPtr<IMedium> dstDisk;

    rc = openMedium(a, pszSrc, DeviceType_HardDisk, AccessMode_ReadOnly,
                    srcDisk, false /* fForceNewUuidOnOpen */,
                    false /* fSilent */);
    if (FAILED(rc))
        return 1;

    do
    {
        /* open/create destination hard disk */
        if (fExisting)
        {
            rc = openMedium(a, pszDst, DeviceType_HardDisk,
                            AccessMode_ReadWrite, dstDisk,
                            false /* fForceNewUuidOnOpen */,
                            false /* fSilent */);
            if (FAILED(rc))
                break;

            /* Perform accessibility check now. */
            MediumState_T state;
            CHECK_ERROR_BREAK(dstDisk, RefreshState(&state));
            CHECK_ERROR_BREAK(dstDisk, COMGETTER(Format)(format.asOutParam()));
        }
        else
        {
            /* use the format of the source hard disk if unspecified */
            if (format.isEmpty())
                CHECK_ERROR_BREAK(srcDisk, COMGETTER(Format)(format.asOutParam()));
            rc = createHardDisk(a, Utf8Str(format).c_str(), pszDst, dstDisk);
            if (FAILED(rc))
                break;
        }

        ComPtr<IProgress> progress;
        com::SafeArray<MediumVariant_T> l_variants(sizeof(MediumVariant_T)*8);

        for (ULONG i = 0; i < l_variants.size(); ++i)
        {
            ULONG temp = DiskVariant;
            temp &= 1<<i;
            l_variants [i] = (MediumVariant_T)temp;
        }

        CHECK_ERROR_BREAK(srcDisk, CloneTo(dstDisk, ComSafeArrayAsInParam(l_variants), NULL, progress.asOutParam()));

        rc = showProgress(progress);
        CHECK_PROGRESS_ERROR_BREAK(progress, ("Failed to clone hard disk"));

        Bstr uuid;
        CHECK_ERROR_BREAK(dstDisk, COMGETTER(Id)(uuid.asOutParam()));

        RTPrintf("Clone hard disk created in format '%ls'. UUID: %s\n",
                 format.raw(), Utf8Str(uuid).c_str());
    }
    while (0);

    return SUCCEEDED(rc) ? 0 : 1;
}
Example #30
0
/**
 * Sets the general Guest Additions information like
 * API (interface) version and OS type.  Gets called by
 * vmmdevUpdateGuestInfo.
 *
 * @param aInterfaceVersion
 * @param aOsType
 */
void Guest::setAdditionsInfo(Bstr aInterfaceVersion, VBOXOSTYPE aOsType)
{
    RTTIMESPEC TimeSpecTS;
    RTTimeNow(&TimeSpecTS);

    AutoCaller autoCaller(this);
    AssertComRCReturnVoid(autoCaller.rc());

    AutoWriteLock alock(this COMMA_LOCKVAL_SRC_POS);


    /*
     * Note: The Guest Additions API (interface) version is deprecated
     * and will not be used anymore!  We might need it to at least report
     * something as version number if *really* ancient Guest Additions are
     * installed (without the guest version + revision properties having set).
     */
    mData.mInterfaceVersion = aInterfaceVersion;

    /*
     * Older Additions rely on the Additions API version whether they
     * are assumed to be active or not.  Since newer Additions do report
     * the Additions version *before* calling this function (by calling
     * VMMDevReportGuestInfo2, VMMDevReportGuestStatus, VMMDevReportGuestInfo,
     * in that order) we can tell apart old and new Additions here. Old
     * Additions never would set VMMDevReportGuestInfo2 (which set mData.mAdditionsVersion)
     * so they just rely on the aInterfaceVersion string (which gets set by
     * VMMDevReportGuestInfo).
     *
     * So only mark the Additions as being active (run level = system) when we
     * don't have the Additions version set.
     */
    if (mData.mAdditionsVersionNew.isEmpty())
    {
        if (aInterfaceVersion.isEmpty())
            mData.mAdditionsRunLevel = AdditionsRunLevelType_None;
        else
        {
            mData.mAdditionsRunLevel = AdditionsRunLevelType_System;

            /*
             * To keep it compatible with the old Guest Additions behavior we need to set the
             * "graphics" (feature) facility to active as soon as we got the Guest Additions
             * interface version.
             */
            facilityUpdate(VBoxGuestFacilityType_Graphics, VBoxGuestFacilityStatus_Active,  0 /*fFlags*/, &TimeSpecTS);
        }
    }

    /*
     * Older Additions didn't have this finer grained capability bit,
     * so enable it by default. Newer Additions will not enable this here
     * and use the setSupportedFeatures function instead.
     */
    /** @todo r=bird: I don't get the above comment nor the code below...
     * One talks about capability bits, the one always does something to a facility.
     * Then there is the comment below it all, which is placed like it addresses the
     * mOSTypeId, but talks about something which doesn't remotely like mOSTypeId...
     *
     * Andy, could you please try clarify and make the comments shorter and more
     * coherent! Also, explain why this is important and what depends on it.
     *
     * PS. There is the VMMDEV_GUEST_SUPPORTS_GRAPHICS capability* report... It
     * should come in pretty quickly after this update, normally.
     */
    facilityUpdate(VBoxGuestFacilityType_Graphics,
                   facilityIsActive(VBoxGuestFacilityType_VBoxGuestDriver)
                   ? VBoxGuestFacilityStatus_Active : VBoxGuestFacilityStatus_Inactive,
                   0 /*fFlags*/, &TimeSpecTS); /** @todo the timestamp isn't gonna be right here on saved state restore. */

    /*
     * Note! There is a race going on between setting mAdditionsRunLevel and
     * mSupportsGraphics here and disabling/enabling it later according to
     * its real status when using new(er) Guest Additions.
     */
    mData.mOSTypeId = Global::OSTypeId(aOsType);
}