Пример #1
0
/**
 * Reads a guest property.
 *
 * @returns VBox status code, fully bitched.
 *
 * @param   u32ClientId         The HGCM client ID for the guest property session.
 * @param   pszPropName         The property name.
 * @param   ppszValue           Where to return the value.  This is always set
 *                              to NULL.  Free it using RTStrFree().
 * @param   ppszFlags           Where to return the value flags. Free it
 *                              using RTStrFree().  Optional.
 * @param   puTimestamp         Where to return the timestamp.  This is only set
 *                              on success.  Optional.
 */
int VBoxServiceReadProp(uint32_t u32ClientId, const char *pszPropName,
                        char **ppszValue, char **ppszFlags, uint64_t *puTimestamp)
{
    AssertPtrReturn(pszPropName, VERR_INVALID_POINTER);
    AssertPtrReturn(ppszValue, VERR_INVALID_POINTER);

    uint32_t    cbBuf = _1K;
    void       *pvBuf = NULL;
    int         rc;

    *ppszValue = NULL;

    for (unsigned cTries = 0; cTries < 10; cTries++)
    {
        /*
         * (Re-)Allocate the buffer and try read the property.
         */
        RTMemFree(pvBuf);
        pvBuf = RTMemAlloc(cbBuf);
        if (!pvBuf)
        {
            VBoxServiceError("Guest Property: Failed to allocate %zu bytes\n", cbBuf);
            rc = VERR_NO_MEMORY;
            break;
        }
        char    *pszValue;
        char    *pszFlags;
        uint64_t uTimestamp;
        rc = VbglR3GuestPropRead(u32ClientId, pszPropName,
                                 pvBuf, cbBuf,
                                 &pszValue, &uTimestamp, &pszFlags, NULL);
        if (RT_FAILURE(rc))
        {
            if (rc == VERR_BUFFER_OVERFLOW)
            {
                /* try again with a bigger buffer. */
                cbBuf *= 2;
                continue;
            }
            if (rc == VERR_NOT_FOUND)
                VBoxServiceVerbose(2, "Guest Property: %s not found\n", pszPropName);
            else
                VBoxServiceError("Guest Property: Failed to query \"%s\": %Rrc\n", pszPropName, rc);
            break;
        }

        VBoxServiceVerbose(2, "Guest Property: Read \"%s\" = \"%s\", timestamp %RU64n\n",
                           pszPropName, pszValue, uTimestamp);
        *ppszValue = RTStrDup(pszValue);
        if (!*ppszValue)
        {
            VBoxServiceError("Guest Property: RTStrDup failed for \"%s\"\n", pszValue);
            rc = VERR_NO_MEMORY;
            break;
        }

        if (puTimestamp)
            *puTimestamp = uTimestamp;
        if (ppszFlags)
            *ppszFlags = RTStrDup(pszFlags);
        break; /* done */
    }

    if (pvBuf)
        RTMemFree(pvBuf);
    return rc;
}
/**
 * Reads a guest property.
 *
 * @return  IPRT status code.
 * @param   hPAM                    PAM handle.
 * @param   uClientID               Guest property service client ID.
 * @param   pszKey                  Key (name) of guest property to read.
 * @param   fReadOnly               Indicates whether this key needs to be
 *                                  checked if it only can be read (and *not* written)
 *                                  by the guest.
 * @param   pszValue                Buffer where to store the key's value.
 * @param   cbValue                 Size of buffer (in bytes).
 */
static int pam_vbox_read_prop(pam_handle_t *hPAM, uint32_t uClientID,
                              const char *pszKey, bool fReadOnly,
                              char *pszValue, size_t cbValue)
{
    AssertPtrReturn(hPAM, VERR_INVALID_POINTER);
    AssertReturn(uClientID, VERR_INVALID_PARAMETER);
    AssertPtrReturn(pszKey, VERR_INVALID_POINTER);
    AssertPtrReturn(pszValue, VERR_INVALID_POINTER);

    int rc;

    uint64_t u64Timestamp = 0;
    char *pszValTemp;
    char *pszFlags = NULL;
    /* The buffer for storing the data and its initial size.  We leave a bit
     * of space here in case the maximum values are raised. */
    void *pvBuf = NULL;
    uint32_t cbBuf = GUEST_PROP_MAX_VALUE_LEN + GUEST_PROP_MAX_FLAGS_LEN + _1K;

    /* Because there is a race condition between our reading the size of a
     * property and the guest updating it, we loop a few times here and
     * hope.  Actually this should never go wrong, as we are generous
     * enough with buffer space. */
    for (unsigned i = 0; i < 10; i++)
    {
        void *pvTmpBuf = RTMemRealloc(pvBuf, cbBuf);
        if (pvTmpBuf)
        {
            pvBuf = pvTmpBuf;
            rc = VbglR3GuestPropRead(uClientID, pszKey, pvBuf, cbBuf,
                                     &pszValTemp, &u64Timestamp, &pszFlags,
                                     &cbBuf);
        }
        else
            rc = VERR_NO_MEMORY;

        switch (rc)
        {
            case VERR_BUFFER_OVERFLOW:
            {
                /* Buffer too small, try it with a bigger one next time. */
                cbBuf += _1K;
                continue; /* Try next round. */
            }

            default:
                break;
        }

        /* Everything except VERR_BUFFER_OVERLOW makes us bail out ... */
        break;
    }

    if (RT_SUCCESS(rc))
    {
        /* Check security bits. */
        if (pszFlags)
        {
            if (   fReadOnly
                && !RTStrStr(pszFlags, "RDONLYGUEST"))
            {
                /* If we want a property which is read-only on the guest
                 * and it is *not* marked as such, deny access! */
                pam_vbox_error(hPAM, "pam_vbox_read_prop: key \"%s\" should be read-only on guest but it is not\n",
                               pszKey);
                rc = VERR_ACCESS_DENIED;
            }
        }
        else /* No flags, no access! */
        {
            pam_vbox_error(hPAM, "pam_vbox_read_prop: key \"%s\" contains no/wrong flags (%s)\n",
                           pszKey, pszFlags);
            rc = VERR_ACCESS_DENIED;
        }

        if (RT_SUCCESS(rc))
        {
            /* If everything went well copy property value to our destination buffer. */
            if (!RTStrPrintf(pszValue, cbValue, "%s", pszValTemp))
            {
                pam_vbox_error(hPAM, "pam_vbox_read_prop: could not store value of key \"%s\"\n",
                               pszKey);
                rc = VERR_INVALID_PARAMETER;
            }

            if (RT_SUCCESS(rc))
                pam_vbox_log(hPAM, "pam_vbox_read_prop: read key \"%s\"=\"%s\"\n",
                             pszKey, pszValue);
        }
    }

    pam_vbox_log(hPAM, "pam_vbox_read_prop: read key \"%s\" with rc=%Rrc\n",
                 pszKey, rc);
    return rc;
}