/** * 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; }