ExtPackUtil.cpp revision 441579693f771e49eb05f2bd20c316232155675b
1ce069685b24d243eb0464f46d4c56b250c64445vboxsync * VirtualBox Main - Extension Pack Utilities and definitions, VBoxC, VBoxSVC, ++.
c58f1213e628a545081c70e26c6b67a841cff880vboxsync * Copyright (C) 2010-2012 Oracle Corporation
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * This file is part of VirtualBox Open Source Edition (OSE), as
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * available from http://www.virtualbox.org. This file is free software;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * you can redistribute it and/or modify it under the terms of the GNU
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * General Public License (GPL) as published by the Free Software
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Foundation, in version 2 as it comes in the "COPYING" file of the
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync/*******************************************************************************
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync* Header Files *
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync*******************************************************************************/
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Worker for VBoxExtPackLoadDesc that loads the plug-in descriptors.
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * @returns Same as VBoxExtPackLoadDesc.
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * @param pVBoxExtPackElm
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pcPlugIns Where to return the number of plug-ins in the
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param paPlugIns Where to return the plug-in descriptor array.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * (RTMemFree it even on failure)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncvboxExtPackLoadPlugInDescs(const xml::ElementNode *pVBoxExtPackElm,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync uint32_t *pcPlugIns, PVBOXEXTPACKPLUGINDESC *paPlugIns)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /** @todo plug-ins */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Clears the extension pack descriptor.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pExtPackDesc The descriptor to clear.
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsyncstatic void vboxExtPackClearDesc(PVBOXEXTPACKDESC a_pExtPackDesc)
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync * Initializes an extension pack descriptor so that it's safe to call free on
89aedeb1d8af54aba6ae46dbbd256281315c1be6vboxsync * it whatever happens later on.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pExtPackDesc The descirptor to initialize.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncvoid VBoxExtPackInitDesc(PVBOXEXTPACKDESC a_pExtPackDesc)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Load the extension pack descriptor from an XML document.
508452243fd3328f7b9e0405d39fb9dc004e31b8vboxsync * @returns NULL on success, pointer to an error message on failure (caller
508452243fd3328f7b9e0405d39fb9dc004e31b8vboxsync * deletes it).
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pDoc Pointer to the the XML document.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pExtPackDesc Where to store the extension pack descriptor.
f409459bdd4c15cdb8d7fb6c6d54338cce9ac814vboxsyncstatic RTCString *vboxExtPackLoadDescFromDoc(xml::Document *a_pDoc, PVBOXEXTPACKDESC a_pExtPackDesc)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Get the main element and check its version.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const xml::ElementNode *pVBoxExtPackElm = a_pDoc->getRootElement();
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync || strcmp(pVBoxExtPackElm->getName(), "VirtualBoxExtensionPack") != 0)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return new RTCString("No VirtualBoxExtensionPack element");
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (!pVBoxExtPackElm->getAttributeValue("version", strFormatVersion))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return &(new RTCString("Unsupported format version: "))->append(strFormatVersion);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Read and validate mandatory bits.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const xml::ElementNode *pNameElm = pVBoxExtPackElm->findChildElement("Name");
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return new RTCString("The 'Name' element is missing");
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync return &(new RTCString("Invalid name: "))->append(pszName);
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync const xml::ElementNode *pDescElm = pVBoxExtPackElm->findChildElement("Description");
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync return new RTCString("The 'Description' element is missing");
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync return new RTCString("The 'Description' element is empty");
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync return new RTCString("The 'Description' must not contain control characters");
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync const xml::ElementNode *pVersionElm = pVBoxExtPackElm->findChildElement("Version");
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync return new RTCString("The 'Version' element is missing");
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync return new RTCString("The 'Version' element is empty");
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync return &(new RTCString("Invalid version string: "))->append(pszVersion);
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync if (!pVersionElm->getAttributeValue("revision", uRevision))
6e12ccc60ac657fb87e27b7a2b26e0a63bebe024vboxsync if (!pVersionElm->getAttributeValue("edition", pszEdition))
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync return &(new RTCString("Invalid edition string: "))->append(pszEdition);
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync const xml::ElementNode *pMainModuleElm = pVBoxExtPackElm->findChildElement("MainModule");
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync return new RTCString("The 'MainModule' element is missing");
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync const char *pszMainModule = pMainModuleElm->getValue();
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync return new RTCString("The 'MainModule' element is empty");
657b2c9f6d33f08001e5fa6f6e0572dcf0391013vboxsync if (!VBoxExtPackIsValidModuleString(pszMainModule))
9cb702c3a5fd2287c57c7c1e98a61ba9e357b4devboxsync return &(new RTCString("Invalid main module string: "))->append(pszMainModule);
6fe1329154975472e055284198df7fa8e64dee3avboxsync * The VRDE module, optional.
6fe1329154975472e055284198df7fa8e64dee3avboxsync * Accept both none and empty as tokens of no VRDE module.
6fe1329154975472e055284198df7fa8e64dee3avboxsync const xml::ElementNode *pVrdeModuleElm = pVBoxExtPackElm->findChildElement("VRDEModule");
6fe1329154975472e055284198df7fa8e64dee3avboxsync else if (!VBoxExtPackIsValidModuleString(pszVrdeModule))
6fe1329154975472e055284198df7fa8e64dee3avboxsync return &(new RTCString("Invalid VRDE module string: "))->append(pszVrdeModule);
6fe1329154975472e055284198df7fa8e64dee3avboxsync * Whether to show the license, optional. (presense is enough here)
6fe1329154975472e055284198df7fa8e64dee3avboxsync const xml::ElementNode *pShowLicenseElm = pVBoxExtPackElm->findChildElement("ShowLicense");
6fe1329154975472e055284198df7fa8e64dee3avboxsync * Parse plug-in descriptions (last because of the manual memory management).
6fe1329154975472e055284198df7fa8e64dee3avboxsync RTCString *pstrRet = vboxExtPackLoadPlugInDescs(pVBoxExtPackElm, &cPlugIns, &paPlugIns);
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * Everything seems fine, fill in the return values and return successfully.
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * Reads the extension pack descriptor.
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * @returns NULL on success, pointer to an error message on failure (caller
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * deletes it).
2a171646d32f8a15e9820d6fb3bf3f9b9990ca3fvboxsync * @param a_pszDir The directory containing the description file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pExtPackDesc Where to store the extension pack descriptor.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pObjInfo Where to store the object info for the file (unix
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * attribs). Optional.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncRTCString *VBoxExtPackLoadDesc(const char *a_pszDir, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Validate, open and parse the XML file.
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync int vrc = RTPathJoin(szFilePath, sizeof(szFilePath), a_pszDir, VBOX_EXTPACK_DESCRIPTION_NAME);
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync return new RTCString("RTPathJoin failed with %Rrc", vrc);
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync vrc = RTPathQueryInfoEx(szFilePath, &ObjInfo, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync return &(new RTCString())->printf("RTPathQueryInfoEx failed with %Rrc", vrc);
7e837ad8d6aeb3f86520ea7adb61e4eb15f2087evboxsync return new RTCString("The XML file is symlinked, that is not allowed");
31a693ce9a8a9ebbecdcea9f24ce7f912aef4cd1vboxsync return &(new RTCString)->printf("The XML file is not a file (fMode=%#x)", ObjInfo.Attr.fMode);
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync * Hand the xml doc over to the common code.
b986941f0aa5155c7fd37da0aa5876675a7680e4vboxsync return vboxExtPackLoadDescFromDoc(&Doc, a_pExtPackDesc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Reads the extension pack descriptor.
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync * @returns NULL on success, pointer to an error message on failure (caller
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync * deletes it).
cdf129515a2b03bc9d122091ce7656d6e6934cc7vboxsync * @param a_pszDir The directory containing the description file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pExtPackDesc Where to store the extension pack descriptor.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pObjInfo Where to store the object info for the file (unix
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * attribs). Optional.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncRTCString *VBoxExtPackLoadDescFromVfsFile(RTVFSFILE hVfsFile, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Query the object info.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int rc = RTVfsFileQueryInfo(hVfsFile, &ObjInfo, RTFSOBJATTRADD_UNIX);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return &(new RTCString)->printf("RTVfsFileQueryInfo failed: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * The simple approach, read the whole thing into memory and pass this to
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * the XML parser.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /* Check the file size. */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (ObjInfo.cbObject > _1M || ObjInfo.cbObject < 0)
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync return &(new RTCString)->printf("The XML file is too large (%'RU64 bytes)", ObjInfo.cbObject);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /* Rewind to the start of the file. */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTVfsFileSeek(hVfsFile, 0, RTFILE_SEEK_BEGIN, NULL);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return &(new RTCString)->printf("RTVfsFileSeek(,0,BEGIN) failed: %Rrc", rc);
42aef05f4b27fb393967e581be04be455064c80avboxsync /* Allocate memory and read the file content into it. */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return &(new RTCString)->printf("RTMemTmpAlloc(%zu) failed", cbFile);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTVfsFileRead(hVfsFile, pvFile, cbFile, NULL);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync pstrErr = &(new RTCString)->printf("RTVfsFileRead failed: %Rrc", rc);
3a8aa22ef125135ef67bfc396771bcee15ef02dfvboxsync * Parse the file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTCString strFileName = VBOX_EXTPACK_DESCRIPTION_NAME;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Hand the xml doc over to the common code.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync pstrErr = vboxExtPackLoadDescFromDoc(&Doc, a_pExtPackDesc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Frees all resources associated with a extension pack descriptor.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param a_pExtPackDesc The extension pack descriptor which members
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * should be freed.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncvoid VBoxExtPackFreeDesc(PVBOXEXTPACKDESC a_pExtPackDesc)
e48239695d41f806ff02d8a60b97dc20d4822d7avboxsync * Extract the extension pack name from the tarball path.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns String containing the name on success, the caller must delete it.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * NULL if no valid name was found or if we ran out of memory.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszTarball The path to the tarball.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncRTCString *VBoxExtPackExtractNameFromTarballPath(const char *pszTarball)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Skip ahead to the filename part and count the number of characters
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * that matches the criteria for a mangled extension pack name.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync while (RT_C_IS_ALNUM(pszSrc[off]) || pszSrc[off] == '_')
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Check min and max name limits.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Return the unmangled name.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Validates the extension pack name.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns true if valid, false if not.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszName The name to validate.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @sa VBoxExtPackExtractNameFromTarballPath
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return false;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Check the characters making up the name, only english alphabet
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * characters, decimal digits and spaces are allowed.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (!RT_C_IS_ALNUM(pszName[off]) && pszName[off] != ' ')
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return false;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Check min and max name limits.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return false;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return true;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Checks if an alledged manged extension pack name.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns true if valid, false if not.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszMangledName The mangled name to validate.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param cchMax The max number of chars to test.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @sa VBoxExtPackMangleName
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncbool VBoxExtPackIsValidMangledName(const char *pszMangledName, size_t cchMax /*= RTSTR_MAX*/)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return false;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Check the characters making up the name, only english alphabet
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * characters, decimal digits and underscores (=space) are allowed.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (!RT_C_IS_ALNUM(pszMangledName[off]) && pszMangledName[off] != '_')
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return false;
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Check min and max name limits.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return false;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync return true;
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * Mangle an extension pack name so it can be used by a directory or file name.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @returns String containing the mangled name on success, the caller must
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * delete it. NULL on failure.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @param pszName The unmangled name.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @sa VBoxExtPackUnmangleName, VBoxExtPackIsValidMangledName
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsyncRTCString *VBoxExtPackMangleName(const char *pszName)
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync AssertReturn(VBoxExtPackIsValidName(pszName), NULL);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * Unmangle an extension pack name (reverses VBoxExtPackMangleName).
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @returns String containing the mangled name on success, the caller must
4f3d37f3c8ea851c3d57304fac430764b77a84dcvboxsync * delete it. NULL on failure.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @param pszMangledName The mangled name.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @param cchMax The max name length. RTSTR_MAX is fine.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @sa VBoxExtPackMangleName, VBoxExtPackIsValidMangledName
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsyncRTCString *VBoxExtPackUnmangleName(const char *pszMangledName, size_t cchMax)
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync AssertReturn(VBoxExtPackIsValidMangledName(pszMangledName, cchMax), NULL);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync AssertReturn(RT_C_IS_ALNUM(ch) || ch == ' ', NULL);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * Constructs the extension pack directory path.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * A combination of RTPathJoin and VBoxExtPackMangleName.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @returns IPRT status code like RTPathJoin.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @param pszExtPackDir Where to return the directory path.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @param cbExtPackDir The size of the return buffer.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @param pszParentDir The parent directory (".../Extensions").
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @param pszName The extension pack name, unmangled.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsyncint VBoxExtPackCalcDir(char *pszExtPackDir, size_t cbExtPackDir, const char *pszParentDir, const char *pszName)
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync AssertReturn(VBoxExtPackIsValidName(pszName), VERR_INTERNAL_ERROR_5);
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync RTCString *pstrMangledName = VBoxExtPackMangleName(pszName);
8ccde4f32d77b1ad3f02111f28a48ee85abf6779vboxsync int vrc = RTPathJoin(pszExtPackDir, cbExtPackDir, pszParentDir, pstrMangledName->c_str());
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * Validates the extension pack version string.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @returns true if valid, false if not.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsync * @param pszVersion The version string to validate.
b4bcdbd7ac35c938e6f71a6403fe9f3ebf106a07vboxsyncbool VBoxExtPackIsValidVersionString(const char *pszVersion)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync return false;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync /* 1.x.y.z... */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync return false;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync /* upper case string + numbers indicating the build type */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync /** @todo Should probably restrict this to known build types (alpha,
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * beta, rc, ++). */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * Validates the extension pack edition string.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @returns true if valid, false if not.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @param pszEdition The edition string to validate.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsyncbool VBoxExtPackIsValidEditionString(const char *pszEdition)
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync return false;
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * Validates an extension pack module string.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @returns true if valid, false if not.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param pszModule The module string to validate.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsyncbool VBoxExtPackIsValidModuleString(const char *pszModule)
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync return false;
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync /* Restricted charset, no extensions (dots). */
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * RTStrPrintfv wrapper.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @returns @a rc
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param rc The status code to return.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param pszError The error buffer.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param cbError The size of the buffer.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param pszFormat The error message format string.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param ... Format arguments.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsyncstatic int vboxExtPackReturnError(int rc, char *pszError, size_t cbError, const char *pszFormat, ...)
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * RTStrPrintfv wrapper.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param pszError The error buffer.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param cbError The size of the buffer.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param pszFormat The error message format string.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsync * @param ... Format arguments.
a38afdea3cc827dc5964b4ba39a5cae6dbae23bdvboxsyncstatic void vboxExtPackSetError(char *pszError, size_t cbError, const char *pszFormat, ...)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Verifies the manifest and its signature.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns VBox status code, failures with message.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param hManifestFile The xml from the extension pack.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszExtPackName The expected extension pack name. This can be
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * NULL, in which we don't have any expectations.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszError Where to store an error message on failure.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param cbError The size of the buffer @a pszError points to.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic int vboxExtPackVerifyXml(RTVFSFILE hXmlFile, const char *pszExtPackName, char *pszError, size_t cbError)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Load the XML.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTCString *pstrErr = VBoxExtPackLoadDescFromVfsFile(hXmlFile, &ExtPackDesc, NULL);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Check the name.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /** @todo drop this restriction after the old install interface is
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * dropped. */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync && !ExtPackDesc.strName.equalsIgnoreCase(pszExtPackName))
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackReturnError(VERR_NOT_EQUAL, pszError, cbError,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync "The name of the downloaded file and the name stored inside the extension pack does not match"
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync " (xml='%s' file='%s')", ExtPackDesc.strName.c_str(), pszExtPackName);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Verifies the manifest and its signature.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns VBox status code, failures with message.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @param hOurManifest The manifest we compiled.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * @param hManifestFile The manifest file in the extension pack.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param hSignatureFile The manifest signature file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszError Where to store an error message on failure.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param cbError The size of the buffer @a pszError points to.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic int vboxExtPackVerifyManifestAndSignature(RTMANIFEST hOurManifest, RTVFSFILE hManifestFile, RTVFSFILE hSignatureFile,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Read the manifest from the extension pack.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync int rc = RTVfsFileSeek(hManifestFile, 0, RTFILE_SEEK_BEGIN, NULL);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return vboxExtPackReturnError(rc, pszError, cbError, "RTVfsFileSeek failed: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTManifestCreate(0 /*fFlags*/, &hTheirManifest);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return vboxExtPackReturnError(rc, pszError, cbError, "RTManifestCreate failed: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hManifestFile);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTManifestReadStandard(hTheirManifest, hVfsIos);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Compare the manifests.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync static const char *s_apszIgnoreEntries[] =
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync rc = RTManifestEqualsEx(hOurManifest, hTheirManifest, &s_apszIgnoreEntries[0], NULL,
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync * Validate the manifest file signature.
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync /** @todo implement signature stuff */
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync vboxExtPackSetError(pszError, cbError, "Manifest mismatch: %s", szError);
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync vboxExtPackSetError(pszError, cbError, "RTManifestEqualsEx failed: %Rrc", rc);
e48239695d41f806ff02d8a60b97dc20d4822d7avboxsync RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, RTFILE_O_WRITE, true, &hVfsIosStdOut);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVfsIoStrmWrite(hVfsIosStdOut, "Our:\n", sizeof("Our:\n") - 1, true, NULL);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTManifestWriteStandard(hOurManifest, hVfsIosStdOut);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVfsIoStrmWrite(hVfsIosStdOut, "Their:\n", sizeof("Their:\n") - 1, true, NULL);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTManifestWriteStandard(hTheirManifest, hVfsIosStdOut);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "Error parsing '%s': %Rrc", VBOX_EXTPACK_MANIFEST_NAME, rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Verifies the file digest (if specified) and returns the SHA-256 of the file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param hFileManifest Manifest containing a SHA-256 digest of the file
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * that was calculated as the file was processed.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param pszFileDigest SHA-256 digest of the file.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param pStrDigest Where to return the SHA-256 digest. Optional.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param pszError Where to write an error message on failure.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param cbError The size of the @a pszError buffer.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncstatic int vboxExtPackVerifyFileDigest(RTMANIFEST hFileManifest, const char *pszFileDigest,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTCString *pStrDigest, char *pszError, size_t cbError)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Extract the SHA-256 entry for the extpack file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int rc = RTManifestEntryQueryAttr(hFileManifest, "extpack", NULL /*no name*/, RTMANIFEST_ATTR_SHA256,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync szCalculatedDigest, sizeof(szCalculatedDigest), NULL);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Convert the two strings to binary form before comparing.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * We convert the calculated hash even if we don't have anything to
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * compare with, just to validate it.
36a04912b64bea8318327fe0723535f1b3f041b0vboxsync rc = RTSha256FromString(szCalculatedDigest, abCalculatedHash);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTSha256FromString(pszFileDigest, abFileHash);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync if (memcmp(abFileHash, abCalculatedHash, sizeof(abFileHash)))
3933885bc0c2c93436d858a14564c6179ec72872vboxsync vboxExtPackSetError(pszError, cbError, "The extension pack file has changed (SHA-256 mismatch)");
3933885bc0c2c93436d858a14564c6179ec72872vboxsync vboxExtPackSetError(pszError, cbError, "Bad SHA-256 '%s': %Rrc", szCalculatedDigest, rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Set the output hash on success.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync vboxExtPackSetError(pszError, cbError, "Bad SHA-256 '%s': %Rrc", szCalculatedDigest, rc);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync vboxExtPackSetError(pszError, cbError, "RTManifestEntryGetAttr: %Rrc", rc);
060f7ec6ae5c99df18341ef2e1f3e91f4b0c89f1vboxsync * Validates a standard file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Generally all files are
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync * @returns VBox status code, failure message in @a pszError.
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync * @param pszAdjName The adjusted member name.
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync * @param enmType The VFS object type.
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync * @param phVfsObj The pointer to the VFS object handle variable.
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync * This is both input and output.
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync * @param phVfsFile Where to store the handle to the memorized
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync * file. This is NULL for license files.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param pszError Where to write an error message on failure.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * @param cbError The size of the @a pszError buffer.
3933885bc0c2c93436d858a14564c6179ec72872vboxsyncstatic int VBoxExtPackValidateStandardFile(const char *pszAdjName, RTVFSOBJTYPE enmType,
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync PRTVFSOBJ phVfsObj, PRTVFSFILE phVfsFile, char *pszError, size_t cbError)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * Make sure it's a file and that it isn't too large.
3933885bc0c2c93436d858a14564c6179ec72872vboxsync rc = vboxExtPackReturnError(VERR_DUPLICATE, pszError, cbError,
3933885bc0c2c93436d858a14564c6179ec72872vboxsync else if (enmType != RTVFSOBJTYPE_IO_STREAM && enmType != RTVFSOBJTYPE_FILE)
3933885bc0c2c93436d858a14564c6179ec72872vboxsync rc = vboxExtPackReturnError(VERR_NOT_A_FILE, pszError, cbError,
aa0553becec2abc2e781f839ba1d399c31c2c07fvboxsync rc = RTVfsObjQueryInfo(*phVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
3933885bc0c2c93436d858a14564c6179ec72872vboxsync rc = vboxExtPackReturnError(VERR_NOT_A_FILE, pszError, cbError,
3933885bc0c2c93436d858a14564c6179ec72872vboxsync rc = vboxExtPackReturnError(VERR_OUT_OF_RANGE, pszError, cbError,
3933885bc0c2c93436d858a14564c6179ec72872vboxsync "Standard member '%s' is too large: %'RU64 bytes (max 1 MB)",
3933885bc0c2c93436d858a14564c6179ec72872vboxsync * Make an in memory copy of the stream and check that the file
70ca8d009d026a301bf7fa08cd18c6494c45fdeevboxsync * is UTF-8 clean.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(*phVfsObj);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTVfsMemorizeIoStreamAsFile(hVfsIos, RTFILE_O_READ, &hVfsFile);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync RTVFS_VALIDATE_UTF8_BY_RTC_3629 | RTVFS_VALIDATE_UTF8_NO_NULL,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Replace *phVfsObj with the memorized file.
501181107e73684ab109521ba371063734cd1d76vboxsync rc = RTVfsFileSeek(hVfsFile, 0, RTFILE_SEEK_BEGIN, NULL);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "RTVfsFileSeek failed on '%s': %Rrc", pszAdjName, rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "RTVfsMemorizeIoStreamAsFile failed on '%s': %Rrc", pszAdjName, rc);
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync vboxExtPackSetError(pszError, cbError, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszAdjName, rc);
501181107e73684ab109521ba371063734cd1d76vboxsync * Validates a name in an extension pack.
501181107e73684ab109521ba371063734cd1d76vboxsync * We restrict the charset to try make sure the extension pack can be unpacked
501181107e73684ab109521ba371063734cd1d76vboxsync * on all file systems.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns VBox status code, failures with message.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsync * @param pszName The name to validate.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszError Where to store an error message on failure.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param cbError The size of the buffer @a pszError points to.
1207f59aa62006952dbb0bf7700decf34d8caeb2vboxsyncstatic int vboxExtPackValidateMemberName(const char *pszName, char *pszError, size_t cbError)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return vboxExtPackReturnError(VERR_PATH_IS_NOT_RELATIVE, pszError, cbError, "'%s': starts with root spec", pszName);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync /* Character set restrictions. */
28ae9ced88db55943497a8bb98682bc2be513476vboxsync pszErr = "The characters ', \", :, ;, *, ?, |, [, ], <, >, (, ), { and } are not allowed";
28ae9ced88db55943497a8bb98682bc2be513476vboxsync /* Take the simple way out and ban all ".." sequences. */
03a954338932c2b34361f1d27ae2029828db0958vboxsync /* Keep the tree shallow or the hardening checks will fail. */
03a954338932c2b34361f1d27ae2029828db0958vboxsync if (psz - pszName > VBOX_EXTPACK_MAX_MEMBER_NAME_LENGTH)
03a954338932c2b34361f1d27ae2029828db0958vboxsync /* advance */
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return vboxExtPackReturnError(VERR_INVALID_NAME, pszError, cbError,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync "Bad member name '%s' (pos %zu): %s", pszName, (size_t)(psz - pszName), pszErr);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Validates a file in an extension pack.
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync * @returns VBox status code, failures with message.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszName The name of the file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param hVfsObj The VFS object.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszError Where to store an error message on failure.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param cbError The size of the buffer @a pszError points to.
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsyncstatic int vboxExtPackValidateMemberFile(const char *pszName, RTVFSOBJ hVfsObj, char *pszError, size_t cbError)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int rc = vboxExtPackValidateMemberName(pszName, pszError, cbError);
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackReturnError(VERR_OUT_OF_RANGE, pszError, cbError,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync "'%s': too large (%'RU64 bytes)",
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync rc = vboxExtPackReturnError(VERR_NOT_A_FILE, pszError, cbError,
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync "The alleged file '%s' has a mode mask stating otherwise (%RTfmode)",
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync vboxExtPackSetError(pszError, cbError, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc);
5af5f66dd66e8ed177bcb8b429a1c2f3093ab406vboxsync * Validates a directory in an extension pack.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns VBox status code, failures with message.
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsync * @param pszName The name of the directory.
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsync * @param hVfsObj The VFS object.
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsync * @param pszError Where to store an error message on failure.
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsync * @param cbError The size of the buffer @a pszError points to.
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsyncstatic int vboxExtPackValidateMemberDir(const char *pszName, RTVFSOBJ hVfsObj, char *pszError, size_t cbError)
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsync int rc = vboxExtPackValidateMemberName(pszName, pszError, cbError);
e4cab07522ccc54b3232ed0f7b6c11ddc3a99572vboxsync rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackReturnError(VERR_NOT_A_DIRECTORY, pszError, cbError,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync "The alleged directory '%s' has a mode mask saying differently (%RTfmode)",
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Validates a member of an extension pack.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns VBox status code, failures with message.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszName The name of the directory.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param enmType The object type.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param hVfsObj The VFS object.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszError Where to store an error message on failure.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param cbError The size of the buffer @a pszError points to.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncint VBoxExtPackValidateMember(const char *pszName, RTVFSOBJTYPE enmType, RTVFSOBJ hVfsObj, char *pszError, size_t cbError)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackValidateMemberFile(pszName, hVfsObj, pszError, cbError);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackValidateMemberDir(pszName, hVfsObj, pszError, cbError);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackReturnError(VERR_UNEXPECTED_FS_OBJ_TYPE, pszError, cbError,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync "'%s' is not a file or directory (enmType=%d)", pszName, enmType);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Rewinds the tarball file handle and creates a gunzip | tar chain that
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * results in a filesystem stream.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns VBox status code, failures with message.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param hTarballFile The handle to the tarball file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszError Where to store an error message on failure.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param cbError The size of the buffer @a pszError points to.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param phTarFss Where to return the filesystem stream handle.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param phFileManifest Where to return a manifest where the tarball is
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * gettting hashed. The entry will be called
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * "extpack" and be ready when the file system
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * stream is at an end. Optional.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncint VBoxExtPackOpenTarFss(RTFILE hTarballFile, char *pszError, size_t cbError, PRTVFSFSSTREAM phTarFss, PRTMANIFEST phFileManifest)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Rewind the file and set up a VFS chain for it.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int rc = RTFileSeek(hTarballFile, 0, RTFILE_SEEK_BEGIN, NULL);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return vboxExtPackReturnError(rc, pszError, cbError, "Failed seeking to the start of the tarball: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTVfsIoStrmFromRTFile(hTarballFile, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN, true /*fLeaveOpen*/,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync return vboxExtPackReturnError(rc, pszError, cbError, "RTVfsIoStrmFromRTFile failed: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTManifestCreate(0 /*fFlags*/, &hFileManifest);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTManifestEntryAddPassthruIoStream(hFileManifest, hTarballIos, "extpack", RTMANIFEST_ATTR_SHA256, true /*read*/, &hPtIos);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTZipGzipDecompressIoStream(hPtIos, 0 /*fFlags*/, &hGunzipIos);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTZipTarFsStreamFromIoStream(hGunzipIos, 0 /*fFlags*/, &hTarFss);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "RTZipTarFsStreamFromIoStream failed: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "RTZipGzipDecompressIoStream failed: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "RTManifestEntryAddPassthruIoStream failed: %Rrc", rc);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "RTManifestCreate failed: %Rrc", rc);
c9e3f6ad81ea9a279ffb537720699e552882c40avboxsync * Validates the extension pack tarball prior to unpacking.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Operations performed:
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * - Mandatory files.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * - Manifest check.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * - Manifest seal check.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * - XML check, match name.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @returns VBox status code, failures with message.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param hTarballFile The handle to open the @a pszTarball file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszExtPackName The name of the extension pack name. NULL if
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * the name is not fixed.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszTarball The name of the tarball in case we have to
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * complain about something.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszTarballDigest The SHA-256 digest of the tarball. Empty string
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * if no digest available.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pszError Where to store an error message on failure.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param cbError The size of the buffer @a pszError points to.
629169500a4e1696f37dd3118a791d68278f71davboxsync * @param phValidManifest Where to optionally return the handle to fully
629169500a4e1696f37dd3118a791d68278f71davboxsync * validated the manifest for the extension pack.
629169500a4e1696f37dd3118a791d68278f71davboxsync * This includes all files.
629169500a4e1696f37dd3118a791d68278f71davboxsync * @param phXmlFile Where to optionally return the memorized XML
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * @param pStrDigest Where to return the digest of the file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Optional.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsyncint VBoxExtPackValidateTarball(RTFILE hTarballFile, const char *pszExtPackName,
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync const char *pszTarball, const char *pszTarballDigest,
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync PRTMANIFEST phValidManifest, PRTVFSFILE phXmlFile, RTCString *pStrDigest)
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Clear return values.
fb1975a6972d89de9e515bed0248db93f04ec9d8vboxsync * Open the tar.gz filesystem stream and set up an manifest in-memory file.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync int rc = VBoxExtPackOpenTarFss(hTarballFile, pszError, cbError, &hTarFss, &hFileManifest);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTManifestCreate(0 /*fFlags*/, &hOurManifest);
94c4b844625733fedcd2b473c207981b31316bd9vboxsync * Process the tarball (would be nice to move this to a function).
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * Get the next stream object.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = RTVfsFsStrmNext(hTarFss, &pszName, &enmType, &hVfsObj);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync vboxExtPackSetError(pszError, cbError, "RTVfsFsStrmNext failed: %Rrc", rc);
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync const char *pszAdjName = pszName[0] == '.' && pszName[1] == '/' ? &pszName[2] : pszName;
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync * Check the type & name validity, performing special tests on
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync * standard extension pack member files.
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync * N.B. We will always reach the end of the loop before breaking on
b2c92fb03e119c7de54f86a32fae9c1d59bc479evboxsync * failure - cleanup reasons.
ae16af2d7d3c99d359094a7f19f5937efc2e66bdvboxsync rc = VBoxExtPackValidateMember(pszName, enmType, hVfsObj, pszError, cbError);
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync if (!strcmp(pszAdjName, VBOX_EXTPACK_DESCRIPTION_NAME))
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync else if (!strcmp(pszAdjName, VBOX_EXTPACK_MANIFEST_NAME))
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync else if (!strcmp(pszAdjName, VBOX_EXTPACK_SIGNATURE_NAME))
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync else if (!strncmp(pszAdjName, VBOX_EXTPACK_LICENSE_NAME_PREFIX, sizeof(VBOX_EXTPACK_LICENSE_NAME_PREFIX) - 1))
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync rc = VBoxExtPackValidateStandardFile(pszAdjName, enmType, &hVfsObj, NULL, pszError, cbError);
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync rc = VBoxExtPackValidateStandardFile(pszAdjName, enmType, &hVfsObj, phVfsFile, pszError, cbError);
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync * Add any I/O stream to the manifest
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj);
1991e77b43953f6187cca21f5616093e9aa60bd3vboxsync rc = RTManifestEntryAddIoStream(hOurManifest, hVfsIos, pszAdjName, RTMANIFEST_ATTR_SIZE | RTMANIFEST_ATTR_SHA256);
1991e77b43953f6187cca21f5616093e9aa60bd3vboxsync vboxExtPackSetError(pszError, cbError, "RTManifestEntryAddIoStream failed on '%s': %Rrc", pszAdjName, rc);
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync * Clean up and break out on failure.
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync * Check the integrity of the tarball file.
9ce5d949e4f1572d445a5c0aecabe9de8b672c99vboxsync rc = vboxExtPackVerifyFileDigest(hFileManifest, pszTarballDigest, pStrDigest, pszError, cbError);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * If we've successfully processed the tarball, verify that the
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync * mandatory files are present.
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_DESCRIPTION_NAME);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_MANIFEST_NAME);
4328e87247f4a96449677e199c7e99ef516fc1cevboxsync rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_SIGNATURE_NAME);
rc = vboxExtPackVerifyManifestAndSignature(hOurManifest, hManifestFile, hSignatureFile, pszError, cbError);
if (phValidManifest)
if (phXmlFile)
return rc;