RTDECL(uint32_t) RTMpGetMaxFrequency(RTCPUID idCpu)
{
    char szFreqLevels[20]; /* Should be enough to get the highest level which is always the first. */
    size_t cbFreqLevels = sizeof(szFreqLevels);

    if (!RTMpIsCpuOnline(idCpu))
        return 0;

    memset(szFreqLevels, 0, sizeof(szFreqLevels));

    /*
     * CPU 0 has the freq levels entry. ENOMEM is ok as we don't need all supported
     * levels but only the first one.
     */
    int rc = sysctlbyname("dev.cpu.0.freq_levels", szFreqLevels, &cbFreqLevels, NULL, NULL);
    if (   (rc && (errno != ENOMEM))
        || (cbFreqLevels == 0))
        return 0;

    /* Clear everything starting from the '/' */
    unsigned i = 0;

    do
    {
        if (szFreqLevels[i] == '/')
        {
            memset(&szFreqLevels[i], 0, sizeof(szFreqLevels) - i);
            break;
        }
        i++;
    } while (i < sizeof(szFreqLevels));

    /* Returns 0 on failure. */
    return RTStrToUInt32(szFreqLevels);
}
DECLINLINE(int) vboxNetAdpGetUnitByName(const char *pcszName)
{
    uint32_t iUnit = RTStrToUInt32(pcszName + sizeof(VBOXNETADP_NAME) - 1);
    bool fOld;

    if (iUnit >= VBOXNETADP_MAX_UNITS)
        return -1;

    fOld = ASMAtomicBitTestAndSet(g_aUnits, iUnit);
    return fOld ? -1 : (int)iUnit;
}
Beispiel #3
0
/**
 * Returns a 32-bit unsigned integer of a specified key.
 *
 * @return  IPRT status code. VERR_NOT_FOUND if key was not found.
 * @param  pszKey               Name of key to get the value for.
 * @param  puVal                Pointer to value to return.
 */
int GuestProcessStreamBlock::GetUInt32Ex(const char *pszKey, uint32_t *puVal) const
{
    AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
    AssertPtrReturn(puVal, VERR_INVALID_POINTER);
    const char *pszValue = GetString(pszKey);
    if (pszValue)
    {
        *puVal = RTStrToUInt32(pszValue);
        return VINF_SUCCESS;
    }
    return VERR_NOT_FOUND;
}
Beispiel #4
0
int localMappings(const ComNatPtr& nat, AddressToOffsetMapping& mapping)
{
    mapping.clear();

    ComBstrArray strs;
    size_t cStrs;
    HRESULT hrc = nat->COMGETTER(LocalMappings)(ComSafeArrayAsOutParam(strs));
    if (   SUCCEEDED(hrc)
            && (cStrs = strs.size()))
    {
        for (size_t i = 0; i < cStrs; ++i)
        {
            char szAddr[17];
            RTNETADDRIPV4 ip4addr;
            char *pszTerm;
            uint32_t u32Off;
            com::Utf8Str strLo2Off(strs[i]);
            const char *pszLo2Off = strLo2Off.c_str();

            RT_ZERO(szAddr);

            pszTerm = RTStrStr(pszLo2Off, "=");

            if (   pszTerm
                    && (pszTerm - pszLo2Off) <= INET_ADDRSTRLEN)
            {
                memcpy(szAddr, pszLo2Off, (pszTerm - pszLo2Off));
                int rc = RTNetStrToIPv4Addr(szAddr, &ip4addr);
                if (RT_SUCCESS(rc))
                {
                    u32Off = RTStrToUInt32(pszTerm + 1);
                    if (u32Off != 0)
                        mapping.insert(
                            AddressToOffsetMapping::value_type(ip4addr, u32Off));
                }
            }
        }
    }
    else
        return VERR_NOT_FOUND;

    return VINF_SUCCESS;
}
Beispiel #5
0
uint32_t CollectorSolaris::getInstance(const char *pszIfaceName, char *pszDevName)
{
    /*
     * Get the instance number from the interface name, then clip it off.
     */
    int cbInstance = 0;
    int cbIface = strlen(pszIfaceName);
    const char *pszEnd = pszIfaceName + cbIface - 1;
    for (int i = 0; i < cbIface - 1; i++)
    {
        if (!RT_C_IS_DIGIT(*pszEnd))
            break;
        cbInstance++;
        pszEnd--;
    }

    uint32_t uInstance = RTStrToUInt32(pszEnd + 1);
    strncpy(pszDevName, pszIfaceName, cbIface - cbInstance);
    pszDevName[cbIface - cbInstance] = '\0';
    return uInstance;
}
static uint32_t getInterfaceSpeed(const char *pszName)
{
    /*
     * I wish I could do simple ioctl here, but older kernels require root
     * privileges for any ethtool commands.
     */
    char szBuf[256];
    uint32_t uSpeed = 0;
    /* First, we try to retrieve the speed via sysfs. */
    RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/speed", pszName);
    FILE *fp = fopen(szBuf, "r");
    if (fp)
    {
        if (fscanf(fp, "%u", &uSpeed) != 1)
            uSpeed = 0;
        fclose(fp);
    }
    if (uSpeed == 10)
    {
        /* Check the cable is plugged in at all */
        unsigned uCarrier = 0;
        RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/carrier", pszName);
        fp = fopen(szBuf, "r");
        if (fp)
        {
            if (fscanf(fp, "%u", &uCarrier) != 1 || uCarrier == 0)
                uSpeed = 0;
            fclose(fp);
        }
    }
    
    if (uSpeed == 0)
    {
        /* Failed to get speed via sysfs, go to plan B. */
        int rc = NetIfAdpCtlOut(pszName, "speed", szBuf, sizeof(szBuf));
        if (RT_SUCCESS(rc))
            uSpeed = RTStrToUInt32(szBuf);
    }
    return uSpeed;
}
RTR3DECL(bool) RTProcIsRunningByName(const char *pszName)
{
    /*
     * Quick validation.
     */
    if (!pszName)
        return false;

    bool const fWithPath = RTPathHavePath(pszName);

    /*
     * Enumerate /proc.
     */
    RTDIR hDir;
    int rc = RTDirOpen(&hDir, "/proc");
    AssertMsgRCReturn(rc, ("RTDirOpen on /proc failed: rc=%Rrc\n", rc), false);
    if (RT_SUCCESS(rc))
    {
        RTDIRENTRY DirEntry;
        while (RT_SUCCESS(RTDirRead(hDir, &DirEntry, NULL)))
        {
            /*
             * Filter numeric directory entries only.
             */
            if (   (   DirEntry.enmType == RTDIRENTRYTYPE_DIRECTORY
                    || DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN)
                && RTStrToUInt32(DirEntry.szName) > 0)
            {
                /*
                 * Try readlink on exe first since it's more faster and reliable.
                 * Fall back on reading the first line in cmdline if that fails
                 * (access errors typically). cmdline is unreliable as it might
                 * contain whatever the execv caller passes as argv[0].
                 */
                char szName[RTPATH_MAX];
                RTStrPrintf(szName, sizeof(szName), "/proc/%s/exe", &DirEntry.szName[0]);
                char szExe[RTPATH_MAX];
                int cchLink = readlink(szName, szExe, sizeof(szExe) - 1);
                if (    cchLink > 0
                    &&  (size_t)cchLink < sizeof(szExe))
                {
                    szExe[cchLink] = '\0';
                    rc = VINF_SUCCESS;
                }
                else
                {
                    RTStrPrintf(szName, sizeof(szName), "/proc/%s/cmdline", &DirEntry.szName[0]);
                    PRTSTREAM pStream;
                    rc = RTStrmOpen(szName, "r", &pStream);
                    if (RT_SUCCESS(rc))
                    {
                        rc = RTStrmGetLine(pStream, szExe, sizeof(szExe));
                        RTStrmClose(pStream);
                    }
                }
                if (RT_SUCCESS(rc))
                {
                    /*
                     * We are interested on the file name part only.
                     */
                    char const *pszProcName = fWithPath ? szExe : RTPathFilename(szExe);
                    if (RTStrCmp(pszProcName, pszName) == 0)
                    {
                        /* Found it! */
                        RTDirClose(hDir);
                        return true;
                    }
                }
            }
        }
        RTDirClose(hDir);
    }

    return false;
}
Beispiel #8
0
int main(int argc, char **argv)
{
    int rcRet = 0;
    int i;
    int rc;
    int cIterations = argc > 1 ? RTStrToUInt32(argv[1]) : 32;
    if (cIterations == 0)
        cIterations = 64;

    /*
     * Init.
     */
    RTR3InitExe(argc, &argv, 0);
    PSUPDRVSESSION pSession;
    rc = SUPR3Init(&pSession);
    rcRet += rc != 0;
    RTPrintf("tstInt: SUPR3Init -> rc=%Rrc\n", rc);
    char szFile[RTPATH_MAX];
    if (!rc)
    {
        rc = RTPathExecDir(szFile, sizeof(szFile) - sizeof("/VMMR0.r0"));
    }
    char szAbsFile[RTPATH_MAX];
    if (RT_SUCCESS(rc))
    {
        strcat(szFile, "/VMMR0.r0");
        rc = RTPathAbs(szFile, szAbsFile, sizeof(szAbsFile));
    }
    if (RT_SUCCESS(rc))
    {
        /*
         * Load VMM code.
         */
        rc = SUPR3LoadVMM(szAbsFile);
        if (RT_SUCCESS(rc))
        {
            /*
             * Create a fake 'VM'.
             */
            PVMR0 pVMR0 = NIL_RTR0PTR;
            PVM pVM = NULL;
            const unsigned cPages = RT_ALIGN_Z(sizeof(*pVM), PAGE_SIZE) >> PAGE_SHIFT;
            PSUPPAGE paPages = (PSUPPAGE)RTMemAllocZ(cPages * sizeof(SUPPAGE));
            if (paPages)
                rc = SUPR3LowAlloc(cPages, (void **)&pVM, &pVMR0, &paPages[0]);
            else
                rc = VERR_NO_MEMORY;
            if (RT_SUCCESS(rc))
            {
                pVM->pVMRC = 0;
                pVM->pVMR3 = pVM;
                pVM->pVMR0 = pVMR0;
                pVM->paVMPagesR3 = paPages;
                pVM->pSession = pSession;
                pVM->enmVMState = VMSTATE_CREATED;

                rc = SUPR3SetVMForFastIOCtl(pVMR0);
                if (!rc)
                {

                    /*
                     * Call VMM code with invalid function.
                     */
                    for (i = cIterations; i > 0; i--)
                    {
                        rc = SUPR3CallVMMR0(pVMR0, NIL_VMCPUID, VMMR0_DO_SLOW_NOP, NULL);
                        if (rc != VINF_SUCCESS)
                        {
                            RTPrintf("tstInt: SUPR3CallVMMR0 -> rc=%Rrc i=%d Expected VINF_SUCCESS!\n", rc, i);
                            rcRet++;
                            break;
                        }
                    }
                    RTPrintf("tstInt: Performed SUPR3CallVMMR0 %d times (rc=%Rrc)\n", cIterations, rc);

                    /*
                     * The fast path.
                     */
                    if (rc == VINF_SUCCESS)
                    {
                        RTTimeNanoTS();
                        uint64_t StartTS = RTTimeNanoTS();
                        uint64_t StartTick = ASMReadTSC();
                        uint64_t MinTicks = UINT64_MAX;
                        for (i = 0; i < 1000000; i++)
                        {
                            uint64_t OneStartTick = ASMReadTSC();
                            rc = SUPR3CallVMMR0Fast(pVMR0, VMMR0_DO_NOP, 0);
                            uint64_t Ticks = ASMReadTSC() - OneStartTick;
                            if (Ticks < MinTicks)
                                MinTicks = Ticks;

                            if (RT_UNLIKELY(rc != VINF_SUCCESS))
                            {
                                RTPrintf("tstInt: SUPR3CallVMMR0Fast -> rc=%Rrc i=%d Expected VINF_SUCCESS!\n", rc, i);
                                rcRet++;
                                break;
                            }
                        }
                        uint64_t Ticks = ASMReadTSC() - StartTick;
                        uint64_t NanoSecs = RTTimeNanoTS() - StartTS;

                        RTPrintf("tstInt: SUPR3CallVMMR0Fast - %d iterations in %llu ns / %llu ticks. %llu ns / %#llu ticks per iteration. Min %llu ticks.\n",
                                 i, NanoSecs, Ticks, NanoSecs / i, Ticks / i, MinTicks);

                        /*
                         * The ordinary path.
                         */
                        RTTimeNanoTS();
                        StartTS = RTTimeNanoTS();
                        StartTick = ASMReadTSC();
                        MinTicks = UINT64_MAX;
                        for (i = 0; i < 1000000; i++)
                        {
                            uint64_t OneStartTick = ASMReadTSC();
                            rc = SUPR3CallVMMR0Ex(pVMR0, NIL_VMCPUID, VMMR0_DO_SLOW_NOP, 0, NULL);
                            uint64_t OneTicks = ASMReadTSC() - OneStartTick;
                            if (OneTicks < MinTicks)
                                MinTicks = OneTicks;

                            if (RT_UNLIKELY(rc != VINF_SUCCESS))
                            {
                                RTPrintf("tstInt: SUPR3CallVMMR0Ex -> rc=%Rrc i=%d Expected VINF_SUCCESS!\n", rc, i);
                                rcRet++;
                                break;
                            }
                        }
                        Ticks = ASMReadTSC() - StartTick;
                        NanoSecs = RTTimeNanoTS() - StartTS;

                        RTPrintf("tstInt: SUPR3CallVMMR0Ex   - %d iterations in %llu ns / %llu ticks. %llu ns / %#llu ticks per iteration. Min %llu ticks.\n",
                                 i, NanoSecs, Ticks, NanoSecs / i, Ticks / i, MinTicks);
                    }
                }
                else
                {
                    RTPrintf("tstInt: SUPR3SetVMForFastIOCtl failed: %Rrc\n", rc);
                    rcRet++;
                }
            }
            else
            {
                RTPrintf("tstInt: SUPR3ContAlloc(%#zx,,) failed\n", sizeof(*pVM));
                rcRet++;
            }

            /*
             * Unload VMM.
             */
            rc = SUPR3UnloadVMM();
            if (rc)
            {
                RTPrintf("tstInt: SUPR3UnloadVMM failed with rc=%Rrc\n", rc);
                rcRet++;
            }
        }
        else
        {
            RTPrintf("tstInt: SUPR3LoadVMM failed with rc=%Rrc\n", rc);
            rcRet++;
        }

        /*
         * Terminate.
         */
        rc = SUPR3Term(false /*fForced*/);
        rcRet += rc != 0;
        RTPrintf("tstInt: SUPR3Term -> rc=%Rrc\n", rc);
    }
Beispiel #9
0
/** @note To be called only from #AssignMachine() */
HRESULT Session::grabIPCSemaphore()
{
    HRESULT rc = E_FAIL;

    /* open the IPC semaphore based on the sessionId and try to grab it */
    Bstr ipcId;
    rc = mControl->GetIPCId(ipcId.asOutParam());
    AssertComRCReturnRC(rc);

    LogFlowThisFunc(("ipcId='%ls'\n", ipcId.raw()));

#if defined(RT_OS_WINDOWS)

    /*
     *  Since Session is an MTA object, this method can be executed on
     *  any thread, and this thread will not necessarily match the thread on
     *  which close() will be called later. Therefore, we need a separate
     *  thread to hold the IPC mutex and then release it in close().
     */

    mIPCThreadSem = ::CreateEvent(NULL, FALSE, FALSE, NULL);
    AssertMsgReturn(mIPCThreadSem,
                    ("Cannot create an event sem, err=%d", ::GetLastError()),
                    E_FAIL);

    void *data[3];
    data[0] = (void*)(BSTR)ipcId.raw();
    data[1] = (void*)mIPCThreadSem;
    data[2] = 0; /* will get an output from the thread */

    /* create a thread to hold the IPC mutex until signalled to release it */
    RTTHREAD tid;
    int vrc = RTThreadCreate(&tid, IPCMutexHolderThread, (void*)data, 0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder");
    AssertRCReturn(vrc, E_FAIL);

    /* wait until thread init is completed */
    DWORD wrc = ::WaitForSingleObject(mIPCThreadSem, INFINITE);
    AssertMsg(wrc == WAIT_OBJECT_0, ("Wait failed, err=%d\n", ::GetLastError()));
    Assert(data[2]);

    if (wrc == WAIT_OBJECT_0 && data[2])
    {
        /* memorize the event sem we should signal in close() */
        mIPCSem = (HANDLE)data[2];
        rc = S_OK;
    }
    else
    {
        ::CloseHandle(mIPCThreadSem);
        mIPCThreadSem = NULL;
        rc = E_FAIL;
    }

#elif defined(RT_OS_OS2)

    /* We use XPCOM where any message (including close()) can arrive on any
     * worker thread (which will not necessarily match this thread that opens
     * the mutex). Therefore, we need a separate thread to hold the IPC mutex
     * and then release it in close(). */

    int vrc = RTSemEventCreate(&mIPCThreadSem);
    AssertRCReturn(vrc, E_FAIL);

    void *data[3];
    data[0] = (void*)ipcId.raw();
    data[1] = (void*)mIPCThreadSem;
    data[2] = (void*)false; /* will get the thread result here */

    /* create a thread to hold the IPC mutex until signalled to release it */
    vrc = RTThreadCreate(&mIPCThread, IPCMutexHolderThread, (void *) data,
                         0, RTTHREADTYPE_MAIN_WORKER, 0, "IPCHolder");
    AssertRCReturn(vrc, E_FAIL);

    /* wait until thread init is completed */
    vrc = RTThreadUserWait (mIPCThread, RT_INDEFINITE_WAIT);
    AssertReturn(RT_SUCCESS(vrc) || vrc == VERR_INTERRUPTED, E_FAIL);

    /* the thread must succeed */
    AssertReturn((bool)data[2], E_FAIL);

#elif defined(VBOX_WITH_SYS_V_IPC_SESSION_WATCHER)

# ifdef VBOX_WITH_NEW_SYS_V_KEYGEN
    Utf8Str ipcKey = ipcId;
    key_t key = RTStrToUInt32(ipcKey.c_str());
    AssertMsgReturn (key != 0,
                    ("Key value of 0 is not valid for IPC semaphore"),
                    E_FAIL);
# else /* !VBOX_WITH_NEW_SYS_V_KEYGEN */
    Utf8Str semName = ipcId;
    char *pszSemName = NULL;
    RTStrUtf8ToCurrentCP (&pszSemName, semName);
    key_t key = ::ftok (pszSemName, 'V');
    RTStrFree (pszSemName);
# endif /* !VBOX_WITH_NEW_SYS_V_KEYGEN */

    mIPCSem = ::semget (key, 0, 0);
    AssertMsgReturn (mIPCSem >= 0,
                    ("Cannot open IPC semaphore, errno=%d", errno),
                    E_FAIL);

    /* grab the semaphore */
    ::sembuf sop = { 0,  -1, SEM_UNDO };
    int rv = ::semop (mIPCSem, &sop, 1);
    AssertMsgReturn (rv == 0,
                    ("Cannot grab IPC semaphore, errno=%d", errno),
                    E_FAIL);

#else
# error "Port me!"
#endif

    return rc;
}
static int getInterfaceInfo(int iSocket, const char *pszName, PNETIFINFO pInfo)
{
    // Zeroing out pInfo is a bad idea as it should contain both short and long names at
    // this point. So make sure the structure is cleared by the caller if necessary!
    // memset(pInfo, 0, sizeof(*pInfo));
    struct ifreq Req;
    memset(&Req, 0, sizeof(Req));
    strncpy(Req.ifr_name, pszName, sizeof(Req.ifr_name) - 1);
    if (ioctl(iSocket, SIOCGIFHWADDR, &Req) >= 0)
    {
        switch (Req.ifr_hwaddr.sa_family)
        {
        case ARPHRD_ETHER:
            pInfo->enmMediumType = NETIF_T_ETHERNET;
            break;
        default:
            pInfo->enmMediumType = NETIF_T_UNKNOWN;
            break;
        }
        /* Generate UUID from name and MAC address. */
        RTUUID uuid;
        RTUuidClear(&uuid);
        memcpy(&uuid, Req.ifr_name, RT_MIN(sizeof(Req.ifr_name), sizeof(uuid)));
        uuid.Gen.u8ClockSeqHiAndReserved = (uuid.Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
        uuid.Gen.u16TimeHiAndVersion = (uuid.Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
        memcpy(uuid.Gen.au8Node, &Req.ifr_hwaddr.sa_data, sizeof(uuid.Gen.au8Node));
        pInfo->Uuid = uuid;

        memcpy(&pInfo->MACAddress, Req.ifr_hwaddr.sa_data, sizeof(pInfo->MACAddress));

        if (ioctl(iSocket, SIOCGIFADDR, &Req) >= 0)
            memcpy(pInfo->IPAddress.au8,
                   &((struct sockaddr_in *)&Req.ifr_addr)->sin_addr.s_addr,
                   sizeof(pInfo->IPAddress.au8));

        if (ioctl(iSocket, SIOCGIFNETMASK, &Req) >= 0)
            memcpy(pInfo->IPNetMask.au8,
                   &((struct sockaddr_in *)&Req.ifr_addr)->sin_addr.s_addr,
                   sizeof(pInfo->IPNetMask.au8));

        if (ioctl(iSocket, SIOCGIFFLAGS, &Req) >= 0)
            pInfo->enmStatus = Req.ifr_flags & IFF_UP ? NETIF_S_UP : NETIF_S_DOWN;

        FILE *fp = fopen("/proc/net/if_inet6", "r");
        if (fp)
        {
            RTNETADDRIPV6 IPv6Address;
            unsigned uIndex, uLength, uScope, uTmp;
            char szName[30];
            for (;;)
            {
                memset(szName, 0, sizeof(szName));
                int n = fscanf(fp,
                               "%08x%08x%08x%08x"
                               " %02x %02x %02x %02x %20s\n",
                               &IPv6Address.au32[0], &IPv6Address.au32[1],
                               &IPv6Address.au32[2], &IPv6Address.au32[3],
                               &uIndex, &uLength, &uScope, &uTmp, szName);
                if (n == EOF)
                    break;
                if (n != 9 || uLength > 128)
                {
                    Log(("getInterfaceInfo: Error while reading /proc/net/if_inet6, n=%d uLength=%u\n",
                         n, uLength));
                    break;
                }
                if (!strcmp(Req.ifr_name, szName))
                {
                    pInfo->IPv6Address.au32[0] = htonl(IPv6Address.au32[0]);
                    pInfo->IPv6Address.au32[1] = htonl(IPv6Address.au32[1]);
                    pInfo->IPv6Address.au32[2] = htonl(IPv6Address.au32[2]);
                    pInfo->IPv6Address.au32[3] = htonl(IPv6Address.au32[3]);
                    ASMBitSetRange(&pInfo->IPv6NetMask, 0, uLength);
                }
            }
            fclose(fp);
        }
        /*
         * Don't even try to get speed for non-Ethernet interfaces, it only
         * produces errors.
         */
        pInfo->uSpeedMbits = 0;
        if (pInfo->enmMediumType == NETIF_T_ETHERNET)
        {
            /*
             * I wish I could do simple ioctl here, but older kernels require root
             * privileges for any ethtool commands.
             */
            char szBuf[256];
            /* First, we try to retrieve the speed via sysfs. */
            RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/speed", pszName);
            fp = fopen(szBuf, "r");
            if (fp)
            {
                if (fscanf(fp, "%u", &pInfo->uSpeedMbits) != 1)
                    pInfo->uSpeedMbits = 0;
                fclose(fp);
            }
            if (pInfo->uSpeedMbits == 10)
            {
                /* Check the cable is plugged in at all */
                unsigned uCarrier = 0;
                RTStrPrintf(szBuf, sizeof(szBuf), "/sys/class/net/%s/carrier", pszName);
                fp = fopen(szBuf, "r");
                if (fp)
                {
                    if (fscanf(fp, "%u", &uCarrier) != 1 || uCarrier == 0)
                        pInfo->uSpeedMbits = 0;
                    fclose(fp);
                }
            }

            if (pInfo->uSpeedMbits == 0)
            {
                /* Failed to get speed via sysfs, go to plan B. */
                int rc = NetIfAdpCtlOut(pszName, "speed", szBuf, sizeof(szBuf));
                if (RT_SUCCESS(rc))
                    pInfo->uSpeedMbits = RTStrToUInt32(szBuf);
            }
        }
    }
    return VINF_SUCCESS;
}
/*
 * Backend entry points.
 */
static DECLCALLBACK(int) iface_Open(PREMOTEUSBBACKEND pInstance, const char *pszAddress,
                                    size_t cbAddress, PREMOTEUSBDEVICE *ppDevice)
{
    int rc = VINF_SUCCESS;

    RemoteUSBBackend *pThis = (RemoteUSBBackend *)pInstance;

    REMOTEUSBDEVICE *pDevice = (REMOTEUSBDEVICE *)RTMemAllocZ(sizeof(REMOTEUSBDEVICE));

    if (!pDevice)
    {
        rc = VERR_NO_MEMORY;
    }
    else
    {
        /* Parse given address string to find the device identifier.
         * The format is "REMOTEUSB0xAAAABBBB&0xCCCCDDDD", where AAAABBBB is hex device identifier
         * and CCCCDDDD is hex client id.
         */
        if (strncmp(pszAddress, REMOTE_USB_BACKEND_PREFIX_S, REMOTE_USB_BACKEND_PREFIX_LEN) != 0)
        {
            AssertFailed();
            rc = VERR_INVALID_PARAMETER;
        }
        else
        {
            /* Initialize the device structure. */
            pDevice->pOwner = pThis;
            pDevice->fWokenUp = false;

            rc = RTCritSectInit(&pDevice->critsect);
            AssertRC(rc);

            if (RT_SUCCESS(rc))
            {
                pDevice->id = RTStrToUInt32(&pszAddress[REMOTE_USB_BACKEND_PREFIX_LEN]);

                size_t l = strlen(pszAddress);

                if (l >= REMOTE_USB_BACKEND_PREFIX_LEN + strlen("0x12345678&0x87654321"))
                {
                    const char *p = &pszAddress[REMOTE_USB_BACKEND_PREFIX_LEN + strlen("0x12345678")];
                    if (*p == '&')
                    {
                        pDevice->u32ClientId = RTStrToUInt32(p + 1);
                    }
                    else
                    {
                        AssertFailed();
                        rc = VERR_INVALID_PARAMETER;
                    }
                }
                else
                {
                    AssertFailed();
                    rc = VERR_INVALID_PARAMETER;
                }

                if (RT_SUCCESS(rc))
                {
                    VRDE_USB_REQ_OPEN_PARM parm;

                    parm.code = VRDE_USB_REQ_OPEN;
                    parm.id = pDevice->id;

                    pThis->VRDPServer()->SendUSBRequest(pDevice->u32ClientId, &parm, sizeof(parm));
                }
            }
        }
    }

    if (RT_SUCCESS(rc))
    {
        *ppDevice = pDevice;

        pThis->addDevice(pDevice);
    }
    else
    {
        RTMemFree(pDevice);
    }

    return rc;
}
DECLEXPORT(int) pam_sm_authenticate(pam_handle_t *hPAM, int iFlags, int argc, const char **argv)
{
    RT_NOREF1(iFlags);

    /* Parse arguments. */
    for (int i = 0; i < argc; i++)
    {
        if (!RTStrICmp(argv[i], "debug"))
            g_verbosity = 1;
        else
            pam_vbox_error(hPAM, "pam_vbox_authenticate: unknown command line argument \"%s\"\n", argv[i]);
    }
    pam_vbox_log(hPAM, "pam_vbox_authenticate called\n");

    int rc = pam_vbox_init(hPAM);
    if (RT_FAILURE(rc))
        return PAM_SUCCESS; /* Jump out as early as we can to not mess around. */

    bool fFallback = true;

#ifdef VBOX_WITH_GUEST_PROPS
    uint32_t uClientId;
    rc = VbglR3GuestPropConnect(&uClientId);
    if (RT_SUCCESS(rc))
    {
        char szVal[256];
        rc = pam_vbox_read_prop(hPAM, uClientId,
                                "/VirtualBox/GuestAdd/PAM/CredsWait",
                                true /* Read-only on guest */,
                                szVal, sizeof(szVal));
        if (RT_SUCCESS(rc))
        {
            /* All calls which are checked against rc2 are not critical, e.g. it does
             * not matter if they succeed or not. */
            uint32_t uTimeoutMS = RT_INDEFINITE_WAIT; /* Wait infinite by default. */
            int rc2 = pam_vbox_read_prop(hPAM, uClientId,
                                         "/VirtualBox/GuestAdd/PAM/CredsWaitTimeout",
                                         true /* Read-only on guest */,
                                         szVal, sizeof(szVal));
            if (RT_SUCCESS(rc2))
            {
                uTimeoutMS = RTStrToUInt32(szVal);
                if (!uTimeoutMS)
                {
                    pam_vbox_error(hPAM, "pam_vbox_authenticate: invalid waiting timeout value specified, defaulting to infinite timeout\n");
                    uTimeoutMS = RT_INDEFINITE_WAIT;
                }
                else
                    uTimeoutMS = uTimeoutMS * 1000; /* Make ms out of s. */
            }

            rc2 = pam_vbox_read_prop(hPAM, uClientId,
                                     "/VirtualBox/GuestAdd/PAM/CredsMsgWaiting",
                                     true /* Read-only on guest */,
                                     szVal, sizeof(szVal));
            const char *pszWaitMsg = NULL;
            if (RT_SUCCESS(rc2))
                pszWaitMsg = szVal;

            rc2 = vbox_set_msg(hPAM, 0 /* Info message */,
                               pszWaitMsg ? pszWaitMsg : "Waiting for credentials ...");
            if (RT_FAILURE(rc2)) /* Not critical. */
                pam_vbox_error(hPAM, "pam_vbox_authenticate: error setting waiting information message, rc=%Rrc\n", rc2);

            if (RT_SUCCESS(rc))
            {
                /* Before we actuall wait for credentials just make sure we didn't already get credentials
                 * set so that we can skip waiting for them ... */
                rc = pam_vbox_check_creds(hPAM);
                if (rc == VERR_NOT_FOUND)
                {
                    rc = pam_vbox_wait_for_creds(hPAM, uClientId, uTimeoutMS);
                    if (rc == VERR_TIMEOUT)
                    {
                        pam_vbox_log(hPAM, "pam_vbox_authenticate: no credentials given within time\n");

                        rc2 = pam_vbox_read_prop(hPAM, uClientId,
                                                 "/VirtualBox/GuestAdd/PAM/CredsMsgWaitTimeout",
                                                 true /* Read-only on guest */,
                                                 szVal, sizeof(szVal));
                        if (RT_SUCCESS(rc2))
                        {
                            rc2 = vbox_set_msg(hPAM, 0 /* Info message */, szVal);
                            AssertRC(rc2);
                        }
                    }
                    else if (rc == VERR_CANCELLED)
                    {
                        pam_vbox_log(hPAM, "pam_vbox_authenticate: waiting aborted\n");

                        rc2 = pam_vbox_read_prop(hPAM, uClientId,
                                                 "/VirtualBox/GuestAdd/PAM/CredsMsgWaitAbort",
                                                 true /* Read-only on guest */,
                                                 szVal, sizeof(szVal));
                        if (RT_SUCCESS(rc2))
                        {
                            rc2 = vbox_set_msg(hPAM, 0 /* Info message */, szVal);
                            AssertRC(rc2);
                        }
                    }
                }

                /* If we got here we don't need the fallback, so just deactivate it. */
                fFallback = false;
            }
        }

        VbglR3GuestPropDisconnect(uClientId);
    }
#endif /* VBOX_WITH_GUEST_PROPS */

    if (fFallback)
    {
        pam_vbox_log(hPAM, "pam_vbox_authenticate: falling back to old method\n");

        /* If anything went wrong in the code above we just do a credentials
         * check like it was before: Try retrieving the stuff and authenticating. */
        int rc2 = pam_vbox_check_creds(hPAM);
        if (RT_SUCCESS(rc))
            rc = rc2;
    }

    pam_vbox_shutdown(hPAM);

    pam_vbox_log(hPAM, "pam_vbox_authenticate: overall result rc=%Rrc\n", rc);

    /* Never report an error here because if no credentials from the host are available or something
     * went wrong we then let do the authentication by the next module in the stack. */

    /* We report success here because this is all we can do right now -- we passed the credentials
     * to the next PAM module in the block above which then might do a shadow (like pam_unix/pam_unix2)
     * password verification to "really" authenticate the user. */
    return PAM_SUCCESS;
}