Changeset 34787 in vbox
- Timestamp:
- Dec 7, 2010 2:51:18 PM (14 years ago)
- svn:sync-xref-src-repo-rev:
- 68597
- Location:
- trunk/src/VBox
- Files:
-
- 12 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Frontends/VBoxManage/VBoxManageMisc.cpp
r34610 r34787 21 21 *******************************************************************************/ 22 22 #ifndef VBOX_ONLY_DOCS 23 # include <VBox/com/com.h>24 # include <VBox/com/string.h>25 # include <VBox/com/Guid.h>26 # include <VBox/com/array.h>27 # include <VBox/com/ErrorInfo.h>28 # include <VBox/com/errorprint.h>29 # include <VBox/com/EventQueue.h>30 31 # include <VBox/com/VirtualBox.h>23 # include <VBox/com/com.h> 24 # include <VBox/com/string.h> 25 # include <VBox/com/Guid.h> 26 # include <VBox/com/array.h> 27 # include <VBox/com/ErrorInfo.h> 28 # include <VBox/com/errorprint.h> 29 # include <VBox/com/EventQueue.h> 30 31 # include <VBox/com/VirtualBox.h> 32 32 #endif /* !VBOX_ONLY_DOCS */ 33 33 … … 912 912 Bstr bstrTarball(szPath); 913 913 Bstr bstrName; 914 CHECK_ERROR2_RET(ptrExtPackMgr, Install(bstrTarball.raw(), bstrName.asOutParam()), RTEXITCODE_FAILURE); 914 ComPtr<IExtPackFile> ptrExtPackFile; 915 CHECK_ERROR2_RET(ptrExtPackMgr, OpenExtPackFile(bstrTarball.raw(), ptrExtPackFile.asOutParam()), RTEXITCODE_FAILURE); 916 CHECK_ERROR2_RET(ptrExtPackFile, COMGETTER(Name)(bstrName.asOutParam()), RTEXITCODE_FAILURE); 917 CHECK_ERROR2_RET(ptrExtPackFile, Install(), RTEXITCODE_FAILURE); 915 918 RTPrintf("Successfully installed \"%lS\".\n", bstrName.raw()); 916 919 } -
trunk/src/VBox/Frontends/VirtualBox/src/globals/VBoxProblemReporter.cpp
r34781 r34787 45 45 46 46 #if defined (Q_WS_WIN32) 47 # include <Htmlhelp.h>47 # include <Htmlhelp.h> 48 48 #endif 49 49 … … 2110 2110 } 2111 2111 2112 void VBoxProblemReporter::cannotInstallExtPack(const QString &strFilename, const CExtPackManager &extPackManager, QWidget *pParent /* = 0 */) 2112 void VBoxProblemReporter::cannotOpenExtPack(const QString &strFilename, const CExtPackManager &extPackManager, QWidget *pParent /* = 0 */) 2113 { 2114 message (pParent ? pParent : mainWindowShown(), 2115 Error, 2116 tr("Failed to open the Extension Pack <b>%1</b>.").arg(strFilename), 2117 formatErrorInfo(extPackManager)); 2118 } 2119 2120 void VBoxProblemReporter::badExtPackFile(const QString &strFilename, const CExtPackFile &extPackFile, QWidget *pParent /* = 0 */) 2121 { 2122 message (pParent ? pParent : mainWindowShown(), 2123 Error, 2124 tr("Failed to open the Extension Pack <b>%1</b>.").arg(strFilename), 2125 extPackFile.GetWhyUnusable()); 2126 } 2127 2128 void VBoxProblemReporter::cannotInstallExtPack(const QString &strFilename, const CExtPackFile &extPackFile, QWidget *pParent /* = 0 */) 2113 2129 { 2114 2130 message (pParent ? pParent : mainWindowShown(), 2115 2131 Error, 2116 2132 tr("Failed to install the Extension Pack <b>%1</b>.").arg(strFilename), 2117 formatErrorInfo(extPack Manager));2133 formatErrorInfo(extPackFile)); 2118 2134 } 2119 2135 -
trunk/src/VBox/Frontends/VirtualBox/src/globals/VBoxProblemReporter.h
r34740 r34787 338 338 void cannotUpdateGuestAdditions (const CProgress &aProgress, QWidget *aParent /* = NULL */) const; 339 339 340 void cannotInstallExtPack(const QString &strFilename, const CExtPackManager &extPackManager, QWidget *pParent = 0); 340 void cannotOpenExtPack(const QString &strFilename, const CExtPackManager &extPackManager, QWidget *pParent = 0); 341 void badExtPackFile(const QString &strFilename, const CExtPackFile &extPackFile, QWidget *pParent = 0); 342 void cannotInstallExtPack(const QString &strFilename, const CExtPackFile &extPackFile, QWidget *pParent = 0); 341 343 void cannotUninstallExtPack(const QString &strPackName, const CExtPackManager &extPackManager, QWidget *pParent = 0); 342 344 bool confirmRemovingPackage(const QString &strPackName, QWidget *pParent = 0); -
trunk/src/VBox/Frontends/VirtualBox/src/selector/VBoxSelectorWnd.cpp
r34728 r34787 39 39 #include "QIFileDialog.h" 40 40 #include "UIDesktopServices.h" 41 #include "UIGlobalSettingsExtension.h" /* extension pack installation */ 41 42 42 43 #ifdef VBOX_GUI_WITH_SYSTRAY … … 1011 1012 else if (VBoxGlobal::hasAllowedExtension(strFile, VBoxDefs::VBoxExtPackFileExts)) 1012 1013 { 1013 CExtPackManager extPackManager = vboxGlobal().virtualBox().GetExtensionPackManager(); 1014 extPackManager.Install(strFile); 1015 if (!extPackManager.isOk()) 1016 vboxProblem().cannotInstallExtPack(strFile, extPackManager, this); 1014 UIGlobalSettingsExtension::doInstallation(strFile, this, NULL); 1017 1015 } 1018 1016 } -
trunk/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsExtension.cpp
r34596 r34787 104 104 } 105 105 106 /** 107 * Attempt the actual installation. 108 * 109 * This code is shared by UIGlobalSettingsExtension::sltInstallPackage and 110 * VBoxSelectorWnd::sltOpenUrls. 111 * @todo Is there perhaps a better home for this method? 112 * 113 * @returns true if successfully installed, false if not. 114 * @param strFilePath The path to the tarball. 115 * @param pParent The parent widget. 116 * @param pstrExtPackName Where to return the extension pack name. Optional. 117 */ 118 /*static*/ bool UIGlobalSettingsExtension::doInstallation(QString const &strFilePath, QWidget *pParent, QString *pstrExtPackName) 119 { 120 bool fInstalled = false; 121 122 /* 123 * Open the extpack tarball via IExtPackManager. 124 */ 125 CExtPackManager manager = vboxGlobal().virtualBox().GetExtensionPackManager(); 126 CExtPackFile extPackFile = manager.OpenExtPackFile(strFilePath); 127 if (manager.isOk()) 128 { 129 if (pstrExtPackName) 130 *pstrExtPackName = extPackFile.GetName(); 131 if (extPackFile.GetUsable()) 132 { 133 bool fAck = true; 134 /** @todo display big fat warning message. */ 135 136 if (fAck) 137 { 138 /** @todo display licenses. */ 139 } 140 141 /* 142 * Install it if everything was ACKed by the user. 143 */ 144 if (fAck) 145 { 146 extPackFile.Install(); 147 if (extPackFile.isOk()) 148 fInstalled = true; 149 else 150 vboxProblem().cannotInstallExtPack(strFilePath, extPackFile, pParent); 151 } 152 } 153 else 154 vboxProblem().badExtPackFile(strFilePath, extPackFile, pParent); 155 } 156 else 157 vboxProblem().cannotOpenExtPack(strFilePath, manager, pParent); 158 159 return fInstalled; 160 } 161 106 162 /* Load data to cashe from corresponding external object(s), 107 163 * this task COULD be performed in other than GUI thread: */ … … 208 264 extensions << QString("*.%1").arg(VBoxDefs::VBoxExtPackFileExts[i]); 209 265 QString strFilter = tr("Extension package files (%1)").arg(extensions.join(" ")); 266 210 267 /* Create open file dialog: */ 211 268 QStringList fileNames = QIFileDialog::getOpenFileNames(strBaseFolder, strFilter, this, strTitle, 0, true, true); … … 213 270 strFilePath = fileNames.at(0); 214 271 215 /* Install chosen package: */ 272 /* 273 * Install chosen package. 274 */ 216 275 if (!strFilePath.isEmpty()) 217 276 { 218 /* Get package manager: */ 219 CExtPackManager manager = vboxGlobal().virtualBox().GetExtensionPackManager(); 220 /* Install package & get the name of newly installed package: */ 221 QString strAddedPackageName = manager.Install(strFilePath); 222 if (manager.isOk()) 277 QString strExtPackName; 278 if (doInstallation(strFilePath, this, &strExtPackName)) 223 279 { 224 /* Get the newly added package: */ 225 const CExtPack &package = manager.Find(strAddedPackageName); 226 /* Add newly added package into cache: */ 280 /* 281 * Insert the fresly installed extension pack, mark it as 282 * current in the tree and sort by name (col 1). 283 */ 284 CExtPackManager manager = vboxGlobal().virtualBox().GetExtensionPackManager(); 285 const CExtPack &package = manager.Find(strExtPackName); 227 286 m_cache.m_items << fetchData(package); 228 /* Add newly added package into tree: */229 287 UIExtensionPackageItem *pItem = new UIExtensionPackageItem(m_pPackagesTree, m_cache.m_items.last()); 230 /* Set the newly created item as current: */231 288 m_pPackagesTree->setCurrentItem(pItem); 232 /* Sort the tree by <name> column: */233 289 m_pPackagesTree->sortByColumn(1, Qt::AscendingOrder); 234 290 } 235 else vboxProblem().cannotInstallExtPack(strFilePath, manager, this);236 291 } 237 292 } -
trunk/src/VBox/Frontends/VirtualBox/src/settings/global/UIGlobalSettingsExtension.h
r34543 r34787 51 51 UIGlobalSettingsExtension(); 52 52 53 static bool doInstallation(QString const &strFilePath, QWidget *pParent, QString *pstrExtPackName); 54 53 55 protected: 54 56 -
trunk/src/VBox/Main/ExtPackManagerImpl.cpp
r34730 r34787 88 88 /** The file handle of the extension pack file. */ 89 89 RTFILE hExtPackFile; 90 /** Pointer to the extension pack manager. */ 91 ComObjPtr<ExtPackManager> ptrExtPackMgr; 92 93 RTMEMEF_NEW_AND_DELETE_OPERATORS(); 90 94 }; 91 95 … … 119 123 /** Set if we've made the pfnVirtualBoxReady or pfnConsoleReady call. */ 120 124 bool fMadeReadyCall; 125 126 RTMEMEF_NEW_AND_DELETE_OPERATORS(); 121 127 }; 122 128 … … 143 149 /** The current context. */ 144 150 VBOXEXTPACKCTX enmContext; 151 152 RTMEMEF_NEW_AND_DELETE_OPERATORS(); 145 153 }; 146 154 … … 166 174 * @returns COM status code. 167 175 * @param a_pszFile The path to the extension pack file. 168 */ 169 HRESULT ExtPackFile::initWithFile(const char *a_pszFile) 176 * @param a_pExtPackMgr Pointer to the extension pack manager. 177 */ 178 HRESULT ExtPackFile::initWithFile(const char *a_pszFile, ExtPackManager *a_pExtPackMgr) 170 179 { 171 180 AutoInitSpan autoInitSpan(this); … … 181 190 m->strWhyUnusable = tr("ExtPack::init failed"); 182 191 m->strExtPackFile = a_pszFile; 183 184 /* 185 * Probe the extension pack (this code is shared with refresh()). 186 */ 192 m->hExtPackFile = NIL_RTFILE; 193 m->ptrExtPackMgr = a_pExtPackMgr; 194 195 iprt::MiniString *pstrTarName = VBoxExtPackExtractNameFromTarballPath(a_pszFile); 196 if (pstrTarName) 197 { 198 m->Desc.strName = *pstrTarName; 199 delete pstrTarName; 200 pstrTarName = NULL; 201 } 187 202 188 203 autoInitSpan.setSucceeded(); 204 205 /* 206 * Try open the extension pack and check that it is a regular file. 207 */ 208 int vrc = RTFileOpen(&m->hExtPackFile, a_pszFile, 209 RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN); 210 if (RT_FAILURE(vrc)) 211 { 212 if (vrc == VERR_FILE_NOT_FOUND || vrc == VERR_PATH_NOT_FOUND) 213 return initFailed(tr("'%s' file not found"), a_pszFile); 214 return initFailed(tr("RTFileOpen('%s',,) failed with %Rrc"), a_pszFile, vrc); 215 } 216 217 RTFSOBJINFO ObjInfo; 218 vrc = RTFileQueryInfo(m->hExtPackFile, &ObjInfo, RTFSOBJATTRADD_UNIX); 219 if (RT_FAILURE(vrc)) 220 return initFailed(tr("RTFileQueryInfo failed with %Rrc on '%s'"), vrc, a_pszFile); 221 if (!RTFS_IS_FILE(ObjInfo.Attr.fMode)) 222 return initFailed(tr("Not a regular file: %s"), a_pszFile); 223 224 /* 225 * Validate the tarball and extract the XML file. 226 */ 227 char szError[8192]; 228 RTVFSFILE hXmlFile; 229 vrc = VBoxExtPackValidateTarball(m->hExtPackFile, NULL /*pszExtPackName*/, a_pszFile, 230 szError, sizeof(szError), NULL /*phValidManifest*/, &hXmlFile); 231 if (RT_FAILURE(vrc)) 232 return initFailed(tr("%s"), szError); 233 234 /* 235 * Parse the XML. 236 */ 237 iprt::MiniString strSavedName(m->Desc.strName); 238 iprt::MiniString *pStrLoadErr = VBoxExtPackLoadDescFromVfsFile(hXmlFile, &m->Desc, &m->ObjInfoDesc); 239 RTVfsFileRelease(hXmlFile); 240 if (pStrLoadErr != NULL) 241 { 242 m->strWhyUnusable.printf(tr("Failed to the xml file: %s"), pStrLoadErr->c_str()); 243 m->Desc.strName = strSavedName; 244 delete pStrLoadErr; 245 return S_OK; 246 } 247 248 /* 249 * Match the tarball name with the name from the XML. 250 */ 251 /** @todo drop this restriction after the old install interface is 252 * dropped. */ 253 if (!strSavedName.equalsIgnoreCase(m->Desc.strName)) 254 return initFailed(tr("Extension pack name mismatch between the downloaded file and the XML inside it (xml='%s' file='%s')"), 255 m->Desc.strName.c_str(), strSavedName.c_str()); 256 257 m->fUsable = true; 258 m->strWhyUnusable.setNull(); 259 return S_OK; 260 } 261 262 /** 263 * Protected helper that formats the strExtPackFile value. 264 * 265 * @returns S_OK 266 * @param a_pszWhyFmt Why it failed, format string. 267 * @param ... The format arguments. 268 */ 269 HRESULT ExtPackFile::initFailed(const char *a_pszWhyFmt, ...) 270 { 271 va_list va; 272 va_start(va, a_pszWhyFmt); 273 m->strExtPackFile.printfV(a_pszWhyFmt, va); 274 va_end(va); 189 275 return S_OK; 190 276 } … … 208 294 { 209 295 VBoxExtPackFreeDesc(&m->Desc); 296 RTFileClose(m->hExtPackFile); 297 m->hExtPackFile = NIL_RTFILE; 210 298 211 299 delete m; … … 326 414 STDMETHODIMP ExtPackFile::Install(void) 327 415 { 328 return E_NOTIMPL; 416 AutoCaller autoCaller(this); 417 HRESULT hrc = autoCaller.rc(); 418 if (SUCCEEDED(hrc)) 419 { 420 if (m->fUsable) 421 hrc = m->ptrExtPackMgr->doInstall(this); 422 else 423 hrc = setError(E_FAIL, "%s", m->strWhyUnusable.c_str()); 424 } 425 return hrc; 329 426 } 330 427 … … 1452 1549 /* else: ignore, the directory probably does not exist or something. */ 1453 1550 1551 #if 0 1454 1552 /* 1455 1553 * Look for things in the drop zone. … … 1457 1555 if (SUCCEEDED(hrc) && a_fCheckDropZone) 1458 1556 processDropZone(); 1557 #else 1558 NOREF(a_fCheckDropZone); 1559 #endif 1459 1560 1460 1561 if (SUCCEEDED(hrc)) … … 1534 1635 AssertReturn(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON, E_UNEXPECTED); 1535 1636 1536 return E_NOTIMPL; 1537 } 1538 1539 STDMETHODIMP ExtPackManager::Install(IN_BSTR a_bstrTarball, BSTR *a_pbstrName) 1540 { 1541 CheckComArgNotNull(a_bstrTarball); 1542 CheckComArgOutPointerValid(a_pbstrName); 1543 Utf8Str strTarball(a_bstrTarball); 1544 AssertReturn(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON, E_UNEXPECTED); 1545 1546 AutoCaller autoCaller(this); 1547 HRESULT hrc = autoCaller.rc(); 1548 if (SUCCEEDED(hrc)) 1549 { 1550 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); 1551 1552 /* 1553 * Check that the file exists and that we can access it. 1554 */ 1555 if (RTFileExists(strTarball.c_str())) 1556 { 1557 RTFILE hFile; 1558 int vrc = RTFileOpen(&hFile, strTarball.c_str(), 1559 RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN | RTFILE_O_INHERIT); 1560 if (RT_SUCCESS(vrc)) 1561 { 1562 RTFSOBJINFO ObjInfo; 1563 vrc = RTFileQueryInfo(hFile, &ObjInfo, RTFSOBJATTRADD_NOTHING); 1564 if ( RT_SUCCESS(vrc) 1565 && RTFS_IS_FILE(ObjInfo.Attr.fMode)) 1566 { 1567 /* 1568 * Derive the name of the extension pack from the file 1569 * name, saving us the trouble of having to unpack it and 1570 * parse its XML to figure it out. While this restricts 1571 * the filename a bit, it also forces it to be clearer, so 1572 * it shouldn't really be a problem. 1573 */ 1574 iprt::MiniString *pStrName = VBoxExtPackExtractNameFromTarballPath(strTarball.c_str()); 1575 if (pStrName) 1576 { 1577 /* 1578 * Refresh the data we have on the extension pack as it 1579 * may be made stale by direct meddling or some other user. 1580 */ 1581 ExtPack *pExtPack; 1582 hrc = refreshExtPack(pStrName->c_str(), false /*a_fUnsuableIsError*/, &pExtPack); 1583 if (SUCCEEDED(hrc) && !pExtPack) 1584 { 1585 /* 1586 * Run the set-uid-to-root binary that performs the actual 1587 * installation. Then create an object for the packet (we 1588 * do this even on failure, to be on the safe side). 1589 */ 1590 char szTarballFd[64]; 1591 RTStrPrintf(szTarballFd, sizeof(szTarballFd), "0x%RX64", 1592 (uint64_t)RTFileToNative(hFile)); 1593 1594 hrc = runSetUidToRootHelper("install", 1595 "--base-dir", m->strBaseDir.c_str(), 1596 "--cert-dir", m->strCertificatDirPath.c_str(), 1597 "--name", pStrName->c_str(), 1598 "--tarball", strTarball.c_str(), 1599 #ifndef RT_OS_WINDOWS /* Not possible since the app might be launched by some unrelated service. */ 1600 "--tarball-fd", &szTarballFd[0], 1601 #endif 1602 NULL); 1603 RTFileClose(hFile); hFile = NIL_RTFILE; 1604 if (SUCCEEDED(hrc)) 1605 { 1606 hrc = refreshExtPack(pStrName->c_str(), true /*a_fUnsuableIsError*/, &pExtPack); 1607 if (SUCCEEDED(hrc)) 1608 { 1609 LogRel(("ExtPackManager: Successfully installed extension pack '%s'.\n", pStrName->c_str())); 1610 pExtPack->callInstalledHook(m->pVirtualBox, &autoLock); 1611 1612 /* 1613 * Finally, return the name. 1614 */ 1615 hrc = pExtPack->COMGETTER(Name)(a_pbstrName); 1616 } 1617 } 1618 else 1619 { 1620 ErrorInfoKeeper Eik; 1621 refreshExtPack(pStrName->c_str(), false /*a_fUnsuableIsError*/, NULL); 1622 } 1623 } 1624 else if (SUCCEEDED(hrc)) 1625 hrc = setError(E_FAIL, 1626 tr("Extension pack '%s' is already installed." 1627 " In case of a reinstallation, please uninstall it first"), 1628 pStrName->c_str()); 1629 delete pStrName; 1630 } 1631 else 1632 hrc = setError(E_FAIL, tr("Malformed '%s' file name"), strTarball.c_str()); 1633 } 1634 else if (RT_SUCCESS(vrc)) 1635 hrc = setError(E_FAIL, tr("'%s' is not a regular file"), strTarball.c_str()); 1636 else 1637 hrc = setError(E_FAIL, tr("Failed to query info on '%s' (%Rrc)"), strTarball.c_str(), vrc); 1638 RTFileClose(hFile); 1639 } 1640 else 1641 hrc = setError(E_FAIL, tr("Failed to open '%s' (%Rrc)"), strTarball.c_str(), vrc); 1642 } 1643 else if (RTPathExists(strTarball.c_str())) 1644 hrc = setError(E_FAIL, tr("'%s' is not a regular file"), strTarball.c_str()); 1645 else 1646 hrc = setError(E_FAIL, tr("File '%s' was inaccessible or not found"), strTarball.c_str()); 1647 1648 /* 1649 * Do VirtualBoxReady callbacks now for any freshly installed 1650 * extension pack (old ones will not be called). 1651 */ 1652 if (m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON) 1653 { 1654 autoLock.release(); 1655 callAllVirtualBoxReadyHooks(); 1656 } 1657 } 1637 ComObjPtr<ExtPackFile> NewExtPackFile; 1638 HRESULT hrc = NewExtPackFile.createObject(); 1639 if (SUCCEEDED(hrc)) 1640 hrc = NewExtPackFile->initWithFile(strTarball.c_str(), this); 1641 if (SUCCEEDED(hrc)) 1642 NewExtPackFile.queryInterfaceTo(a_ppExtPackFile); 1658 1643 1659 1644 return hrc; … … 2157 2142 } 2158 2143 2159 2144 /** 2145 * Worker for IExtPackFile::Install. 2146 * 2147 * @returns COM status code. 2148 * @param a_pExtPackFile The extension pack file, caller checks that it's 2149 * usable. 2150 */ 2151 HRESULT ExtPackManager::doInstall(ExtPackFile *a_pExtPackFile) 2152 { 2153 AssertReturn(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON, E_UNEXPECTED); 2154 iprt::MiniString const * const pStrName = &a_pExtPackFile->m->Desc.strName; 2155 iprt::MiniString const * const pStrTarball = &a_pExtPackFile->m->strExtPackFile; 2156 2157 AutoCaller autoCaller(this); 2158 HRESULT hrc = autoCaller.rc(); 2159 if (SUCCEEDED(hrc)) 2160 { 2161 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); 2162 2163 /* 2164 * Refresh the data we have on the extension pack as it 2165 * may be made stale by direct meddling or some other user. 2166 */ 2167 ExtPack *pExtPack; 2168 hrc = refreshExtPack(pStrName->c_str(), false /*a_fUnsuableIsError*/, &pExtPack); 2169 if (SUCCEEDED(hrc) && !pExtPack) 2170 { 2171 /* 2172 * Run the privileged helper binary that performs the actual 2173 * installation. Then create an object for the packet (we do this 2174 * even on failure, to be on the safe side). 2175 */ 2176 /** @todo add a hash (SHA-256) of the tarball or maybe just the manifest. */ 2177 hrc = runSetUidToRootHelper("install", 2178 "--base-dir", m->strBaseDir.c_str(), 2179 "--cert-dir", m->strCertificatDirPath.c_str(), 2180 "--name", pStrName->c_str(), 2181 "--tarball", pStrTarball->c_str(), 2182 NULL); 2183 if (SUCCEEDED(hrc)) 2184 { 2185 hrc = refreshExtPack(pStrName->c_str(), true /*a_fUnsuableIsError*/, &pExtPack); 2186 if (SUCCEEDED(hrc)) 2187 { 2188 LogRel(("ExtPackManager: Successfully installed extension pack '%s'.\n", pStrName->c_str())); 2189 pExtPack->callInstalledHook(m->pVirtualBox, &autoLock); 2190 } 2191 } 2192 else 2193 { 2194 ErrorInfoKeeper Eik; 2195 refreshExtPack(pStrName->c_str(), false /*a_fUnsuableIsError*/, NULL); 2196 } 2197 } 2198 else if (SUCCEEDED(hrc)) 2199 hrc = setError(E_FAIL, 2200 tr("Extension pack '%s' is already installed." 2201 " In case of a reinstallation, please uninstall it first"), 2202 pStrName->c_str()); 2203 2204 /* 2205 * Do VirtualBoxReady callbacks now for any freshly installed 2206 * extension pack (old ones will not be called). 2207 */ 2208 if (m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON) 2209 { 2210 autoLock.release(); 2211 callAllVirtualBoxReadyHooks(); 2212 } 2213 } 2214 2215 return hrc; 2216 } 2217 2218 #if 0 2160 2219 /** 2161 2220 * Processes anything new in the drop zone. … … 2241 2300 RTDirClose(pDir); 2242 2301 } 2302 #endif 2243 2303 2244 2304 -
trunk/src/VBox/Main/ExtPackUtil.cpp
r34579 r34787 25 25 #include <iprt/dir.h> 26 26 #include <iprt/file.h> 27 #include <iprt/manifest.h> 27 28 #include <iprt/param.h> 28 29 #include <iprt/path.h> 29 30 #include <iprt/string.h> 31 #include <iprt/vfs.h> 32 #include <iprt/tar.h> 33 #include <iprt/zip.h> 30 34 #include <iprt/cpp/xml.h> 31 35 … … 57 61 58 62 /** 59 * Reads the extension pack descriptor. 60 * 61 * @returns NULL on success, pointer to an error message on failure (caller 62 * deletes it). 63 * @param a_pszDir The directory containing the description file. 64 * @param a_pExtPackDesc Where to store the extension pack descriptor. 65 * @param a_pObjInfo Where to store the object info for the file (unix 66 * attribs). Optional. 67 */ 68 iprt::MiniString *VBoxExtPackLoadDesc(const char *a_pszDir, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo) 69 { 70 /* 71 * Clear the descriptor. 72 */ 63 * Clears the extension pack descriptor. 64 * 65 * @param a_pExtPackDesc The descriptor to clear. 66 */ 67 static void vboxExtPackClearDesc(PVBOXEXTPACKDESC a_pExtPackDesc) 68 { 73 69 a_pExtPackDesc->strName.setNull(); 74 70 a_pExtPackDesc->strDescription.setNull(); … … 79 75 a_pExtPackDesc->cPlugIns = 0; 80 76 a_pExtPackDesc->paPlugIns = NULL; 81 82 /* 83 * Validate, open and parse the XML file. 84 */ 85 char szFilePath[RTPATH_MAX]; 86 int vrc = RTPathJoin(szFilePath, sizeof(szFilePath), a_pszDir, VBOX_EXTPACK_DESCRIPTION_NAME); 87 if (RT_FAILURE(vrc)) 88 return new iprt::MiniString("RTPathJoin failed with %Rrc", vrc); 89 90 RTFSOBJINFO ObjInfo; 91 vrc = RTPathQueryInfoEx(szFilePath, &ObjInfo, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK); 92 if (RT_FAILURE(vrc)) 93 return &(new iprt::MiniString())->printf("RTPathQueryInfoEx failed with %Rrc", vrc); 94 if (a_pObjInfo) 95 *a_pObjInfo = ObjInfo; 96 if (!RTFS_IS_FILE(ObjInfo.Attr.fMode)) 97 { 98 if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode)) 99 return new iprt::MiniString("The XML file is symlinked, that is not allowed"); 100 return &(new iprt::MiniString)->printf("The XML file is not a file (fMode=%#x)", ObjInfo.Attr.fMode); 101 } 102 103 xml::Document Doc; 104 xml::XmlFileParser Parser; 105 try 106 { 107 Parser.read(szFilePath, Doc); 108 } 109 catch (xml::XmlError Err) 110 { 111 return new iprt::MiniString(Err.what()); 112 } 113 77 } 78 79 /** 80 * Load the extension pack descriptor from an XML document. 81 * 82 * @returns NULL on success, pointer to an error message on failure (caller 83 * deletes it). 84 * @param a_pDoc Pointer to the the XML document. 85 * @param a_pExtPackDesc Where to store the extension pack descriptor. 86 */ 87 static iprt::MiniString *vboxExtPackLoadDescFromDoc(xml::Document *a_pDoc, PVBOXEXTPACKDESC a_pExtPackDesc) 88 { 114 89 /* 115 90 * Get the main element and check its version. 116 91 */ 117 const xml::ElementNode *pVBoxExtPackElm = Doc.getRootElement();92 const xml::ElementNode *pVBoxExtPackElm = a_pDoc->getRootElement(); 118 93 if ( !pVBoxExtPackElm 119 94 || strcmp(pVBoxExtPackElm->getName(), "VirtualBoxExtensionPack") != 0) … … 209 184 } 210 185 186 /** 187 * Reads the extension pack descriptor. 188 * 189 * @returns NULL on success, pointer to an error message on failure (caller 190 * deletes it). 191 * @param a_pszDir The directory containing the description file. 192 * @param a_pExtPackDesc Where to store the extension pack descriptor. 193 * @param a_pObjInfo Where to store the object info for the file (unix 194 * attribs). Optional. 195 */ 196 iprt::MiniString *VBoxExtPackLoadDesc(const char *a_pszDir, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo) 197 { 198 vboxExtPackClearDesc(a_pExtPackDesc); 199 200 /* 201 * Validate, open and parse the XML file. 202 */ 203 char szFilePath[RTPATH_MAX]; 204 int vrc = RTPathJoin(szFilePath, sizeof(szFilePath), a_pszDir, VBOX_EXTPACK_DESCRIPTION_NAME); 205 if (RT_FAILURE(vrc)) 206 return new iprt::MiniString("RTPathJoin failed with %Rrc", vrc); 207 208 RTFSOBJINFO ObjInfo; 209 vrc = RTPathQueryInfoEx(szFilePath, &ObjInfo, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK); 210 if (RT_FAILURE(vrc)) 211 return &(new iprt::MiniString())->printf("RTPathQueryInfoEx failed with %Rrc", vrc); 212 if (a_pObjInfo) 213 *a_pObjInfo = ObjInfo; 214 if (!RTFS_IS_FILE(ObjInfo.Attr.fMode)) 215 { 216 if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode)) 217 return new iprt::MiniString("The XML file is symlinked, that is not allowed"); 218 return &(new iprt::MiniString)->printf("The XML file is not a file (fMode=%#x)", ObjInfo.Attr.fMode); 219 } 220 221 xml::Document Doc; 222 { 223 xml::XmlFileParser Parser; 224 try 225 { 226 Parser.read(szFilePath, Doc); 227 } 228 catch (xml::XmlError Err) 229 { 230 return new iprt::MiniString(Err.what()); 231 } 232 } 233 234 /* 235 * Hand the xml doc over to the common code. 236 */ 237 return vboxExtPackLoadDescFromDoc(&Doc, a_pExtPackDesc); 238 } 239 240 /** 241 * Reads the extension pack descriptor. 242 * 243 * @returns NULL on success, pointer to an error message on failure (caller 244 * deletes it). 245 * @param a_pszDir The directory containing the description file. 246 * @param a_pExtPackDesc Where to store the extension pack descriptor. 247 * @param a_pObjInfo Where to store the object info for the file (unix 248 * attribs). Optional. 249 */ 250 iprt::MiniString *VBoxExtPackLoadDescFromVfsFile(RTVFSFILE hVfsFile, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo) 251 { 252 vboxExtPackClearDesc(a_pExtPackDesc); 253 254 /* 255 * Query the object info. 256 */ 257 RTFSOBJINFO ObjInfo; 258 int rc = RTVfsFileQueryInfo(hVfsFile, &ObjInfo, RTFSOBJATTRADD_UNIX); 259 if (RT_FAILURE(rc)) 260 return &(new iprt::MiniString)->printf("RTVfsFileQueryInfo failed: %Rrc", rc); 261 if (a_pObjInfo) 262 *a_pObjInfo = ObjInfo; 263 264 /* 265 * The simple approach, read the whole thing into memory and pass this to 266 * the XML parser. 267 */ 268 269 /* Check the file size. */ 270 if (ObjInfo.cbObject > _1M || ObjInfo.cbObject < 0) 271 return &(new iprt::MiniString)->printf("The XML file is too large (%'RU64 bytes)", ObjInfo.cbObject); 272 size_t const cbFile = (size_t)ObjInfo.cbObject; 273 274 /* Rewind to the start of the file. */ 275 rc = RTVfsFileSeek(hVfsFile, 0, RTFILE_SEEK_BEGIN, NULL); 276 if (RT_FAILURE(rc)) 277 return &(new iprt::MiniString)->printf("RTVfsFileSeek(,0,BEGIN) failed: %Rrc", rc); 278 279 /* Allocate memory and read the file content into it. */ 280 void *pvFile = RTMemTmpAlloc(cbFile); 281 if (!pvFile) 282 return &(new iprt::MiniString)->printf("RTMemTmpAlloc(%zu) failed", cbFile); 283 284 iprt::MiniString *pstrErr = NULL; 285 rc = RTVfsFileRead(hVfsFile, pvFile, cbFile, NULL); 286 if (RT_FAILURE(rc)) 287 pstrErr = &(new iprt::MiniString)->printf("RTVfsFileRead failed: %Rrc", rc); 288 289 /* 290 * Parse the file. 291 */ 292 xml::Document Doc; 293 if (RT_SUCCESS(rc)) 294 { 295 xml::XmlMemParser Parser; 296 iprt::MiniString strFileName = VBOX_EXTPACK_DESCRIPTION_NAME; 297 try 298 { 299 Parser.read(pvFile, cbFile, strFileName, Doc); 300 } 301 catch (xml::XmlError Err) 302 { 303 pstrErr = new iprt::MiniString(Err.what()); 304 rc = VERR_PARSE_ERROR; 305 } 306 } 307 RTMemTmpFree(pvFile); 308 309 /* 310 * Hand the xml doc over to the common code. 311 */ 312 if (RT_SUCCESS(rc)) 313 pstrErr = vboxExtPackLoadDescFromDoc(&Doc, a_pExtPackDesc); 314 315 return pstrErr; 316 } 211 317 212 318 /** … … 232 338 } 233 339 234 235 340 /** 236 341 * Extract the extension pack name from the tarball path. … … 488 593 } 489 594 595 /** 596 * RTStrPrintfv wrapper. 597 * 598 * @returns @a rc 599 * @param rc The status code to return. 600 * @param pszError The error buffer. 601 * @param cbError The size of the buffer. 602 * @param pszFormat The error message format string. 603 * @param ... Format arguments. 604 */ 605 static int vboxExtPackReturnError(int rc, char *pszError, size_t cbError, const char *pszFormat, ...) 606 { 607 va_list va; 608 va_start(va, pszFormat); 609 RTStrPrintfV(pszError, cbError, pszFormat, va); 610 va_end(va); 611 return rc; 612 } 613 614 /** 615 * RTStrPrintfv wrapper. 616 * 617 * @param pszError The error buffer. 618 * @param cbError The size of the buffer. 619 * @param pszFormat The error message format string. 620 * @param ... Format arguments. 621 */ 622 static void vboxExtPackSetError(char *pszError, size_t cbError, const char *pszFormat, ...) 623 { 624 va_list va; 625 va_start(va, pszFormat); 626 RTStrPrintfV(pszError, cbError, pszFormat, va); 627 va_end(va); 628 } 629 630 /** 631 * Verifies the manifest and its signature. 632 * 633 * @returns VBox status code, failures with message. 634 * @param hManifestFile The xml from the extension pack. 635 * @param pszExtPackName The expected extension pack name. This can be 636 * NULL, in which we don't have any expectations. 637 * @param pszError Where to store an error message on failure. 638 * @param cbError The size of the buffer @a pszError points to. 639 */ 640 static int vboxExtPackVerifyXml(RTVFSFILE hXmlFile, const char *pszExtPackName, char *pszError, size_t cbError) 641 { 642 /* 643 * Load the XML. 644 */ 645 VBOXEXTPACKDESC ExtPackDesc; 646 iprt::MiniString *pstrErr = VBoxExtPackLoadDescFromVfsFile(hXmlFile, &ExtPackDesc, NULL); 647 if (pstrErr) 648 { 649 RTStrCopy(pszError, cbError, pstrErr->c_str()); 650 delete pstrErr; 651 return VERR_PARSE_ERROR; 652 } 653 654 /* 655 * Check the name. 656 */ 657 /** @todo drop this restriction after the old install interface is 658 * dropped. */ 659 int rc = VINF_SUCCESS; 660 if ( pszExtPackName 661 && !ExtPackDesc.strName.equalsIgnoreCase(pszExtPackName)) 662 rc = vboxExtPackReturnError(VERR_NOT_EQUAL, pszError, cbError, 663 "The name of the downloaded file and the name stored inside the extension pack does not match" 664 " (xml='%s' file='%s')", ExtPackDesc.strName.c_str(), pszExtPackName); 665 return rc; 666 } 667 668 /** 669 * Verifies the manifest and its signature. 670 * 671 * @returns VBox status code, failures with message. 672 * @param hOurManifest The manifest we compiled. 673 * @param hManifestFile The manifest file in the extension pack. 674 * @param hSignatureFile The manifest signature file. 675 * @param pszError Where to store an error message on failure. 676 * @param cbError The size of the buffer @a pszError points to. 677 */ 678 static int vboxExtPackVerifyManifestAndSignature(RTMANIFEST hOurManifest, RTVFSFILE hManifestFile, RTVFSFILE hSignatureFile, 679 char *pszError, size_t cbError) 680 { 681 /* 682 * Read the manifest from the extension pack. 683 */ 684 int rc = RTVfsFileSeek(hManifestFile, 0, RTFILE_SEEK_BEGIN, NULL); 685 if (RT_FAILURE(rc)) 686 return vboxExtPackReturnError(rc, pszError, cbError, "RTVfsFileSeek failed: %Rrc", rc); 687 688 RTMANIFEST hTheirManifest; 689 rc = RTManifestCreate(0 /*fFlags*/, &hTheirManifest); 690 if (RT_FAILURE(rc)) 691 return vboxExtPackReturnError(rc, pszError, cbError, "RTManifestCreate failed: %Rrc", rc); 692 693 RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hManifestFile); 694 rc = RTManifestReadStandard(hTheirManifest, hVfsIos); 695 RTVfsIoStrmRelease(hVfsIos); 696 if (RT_SUCCESS(rc)) 697 { 698 /* 699 * Compare the manifests. 700 */ 701 static const char *s_apszIgnoreEntries[] = 702 { 703 VBOX_EXTPACK_MANIFEST_NAME, 704 VBOX_EXTPACK_SIGNATURE_NAME, 705 "./" VBOX_EXTPACK_MANIFEST_NAME, 706 "./" VBOX_EXTPACK_SIGNATURE_NAME, 707 NULL 708 }; 709 char szError[RTPATH_MAX]; 710 rc = RTManifestEqualsEx(hOurManifest, hTheirManifest, &s_apszIgnoreEntries[0], NULL, 711 RTMANIFEST_EQUALS_IGN_MISSING_ATTRS /*fFlags*/, 712 szError, sizeof(szError)); 713 if (RT_SUCCESS(rc)) 714 { 715 /* 716 * Validate the manifest file signature. 717 */ 718 /** @todo implement signature stuff */ 719 NOREF(hSignatureFile); 720 721 } 722 else if (rc == VERR_NOT_EQUAL && szError[0]) 723 vboxExtPackSetError(pszError, cbError, "Manifest mismatch: %s", szError); 724 else 725 vboxExtPackSetError(pszError, cbError, "RTManifestEqualsEx failed: %Rrc", rc); 726 #if 0 727 RTVFSIOSTREAM hVfsIosStdOut = NIL_RTVFSIOSTREAM; 728 RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, RTFILE_O_WRITE, true, &hVfsIosStdOut); 729 RTVfsIoStrmWrite(hVfsIosStdOut, "Our:\n", sizeof("Our:\n") - 1, true, NULL); 730 RTManifestWriteStandard(hOurManifest, hVfsIosStdOut); 731 RTVfsIoStrmWrite(hVfsIosStdOut, "Their:\n", sizeof("Their:\n") - 1, true, NULL); 732 RTManifestWriteStandard(hTheirManifest, hVfsIosStdOut); 733 #endif 734 } 735 else 736 vboxExtPackSetError(pszError, cbError, "Error parsing '%s': %Rrc", VBOX_EXTPACK_MANIFEST_NAME, rc); 737 738 RTManifestRelease(hTheirManifest); 739 return rc; 740 } 741 742 743 /** 744 * Validates a name in an extension pack. 745 * 746 * We restrict the charset to try make sure the extension pack can be unpacked 747 * on all file systems. 748 * 749 * @returns VBox status code, failures with message. 750 * @param pszName The name to validate. 751 * @param pszError Where to store an error message on failure. 752 * @param cbError The size of the buffer @a pszError points to. 753 */ 754 static int vboxExtPackValidateMemberName(const char *pszName, char *pszError, size_t cbError) 755 { 756 if (RTPathStartsWithRoot(pszName)) 757 return vboxExtPackReturnError(VERR_PATH_IS_NOT_RELATIVE, pszError, cbError, "'%s': starts with root spec", pszName); 758 759 const char *pszErr = NULL; 760 const char *psz = pszName; 761 int ch; 762 while ((ch = *psz) != '\0') 763 { 764 /* Character set restrictions. */ 765 if (ch < 0 || ch >= 128) 766 { 767 pszErr = "Only 7-bit ASCII allowed"; 768 break; 769 } 770 if (ch <= 31 || ch == 127) 771 { 772 pszErr = "No control characters are not allowed"; 773 break; 774 } 775 if (ch == '\\') 776 { 777 pszErr = "Only backward slashes are not allowed"; 778 break; 779 } 780 if (strchr("'\":;*?|[]<>(){}", ch)) 781 { 782 pszErr = "The characters ', \", :, ;, *, ?, |, [, ], <, >, (, ), { and } are not allowed"; 783 break; 784 } 785 786 /* Take the simple way out and ban all ".." sequences. */ 787 if ( ch == '.' 788 && psz[1] == '.') 789 { 790 pszErr = "Double dot sequence are not allowed"; 791 break; 792 } 793 794 /* Keep the tree shallow or the hardening checks will fail. */ 795 if (psz - pszName > VBOX_EXTPACK_MAX_MEMBER_NAME_LENGTH) 796 { 797 pszErr = "Too long"; 798 break; 799 } 800 801 /* advance */ 802 psz++; 803 } 804 805 if (pszErr) 806 return vboxExtPackReturnError(VERR_INVALID_NAME, pszError, cbError, 807 "Bad member name '%s' (pos %zu): %s", pszName, (size_t)(psz - pszName), pszErr); 808 return RTEXITCODE_SUCCESS; 809 } 810 811 812 /** 813 * Validates a file in an extension pack. 814 * 815 * @returns VBox status code, failures with message. 816 * @param pszName The name of the file. 817 * @param hVfsObj The VFS object. 818 * @param pszError Where to store an error message on failure. 819 * @param cbError The size of the buffer @a pszError points to. 820 */ 821 static int vboxExtPackValidateMemberFile(const char *pszName, RTVFSOBJ hVfsObj, char *pszError, size_t cbError) 822 { 823 int rc = vboxExtPackValidateMemberName(pszName, pszError, cbError); 824 if (RT_SUCCESS(rc)) 825 { 826 RTFSOBJINFO ObjInfo; 827 rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING); 828 if (RT_SUCCESS(rc)) 829 { 830 if (ObjInfo.cbObject >= 9*_1G64) 831 rc = vboxExtPackReturnError(VERR_OUT_OF_RANGE, pszError, cbError, 832 "'%s': too large (%'RU64 bytes)", 833 pszName, (uint64_t)ObjInfo.cbObject); 834 if (!RTFS_IS_FILE(ObjInfo.Attr.fMode)) 835 rc = vboxExtPackReturnError(VERR_NOT_A_FILE, pszError, cbError, 836 "The alleged file '%s' has a mode mask stating otherwise (%RTfmode)", 837 pszName, ObjInfo.Attr.fMode); 838 } 839 else 840 vboxExtPackSetError(pszError, cbError, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc); 841 } 842 return rc; 843 } 844 845 846 /** 847 * Validates a directory in an extension pack. 848 * 849 * @returns VBox status code, failures with message. 850 * @param pszName The name of the directory. 851 * @param hVfsObj The VFS object. 852 * @param pszError Where to store an error message on failure. 853 * @param cbError The size of the buffer @a pszError points to. 854 */ 855 static int vboxExtPackValidateMemberDir(const char *pszName, RTVFSOBJ hVfsObj, char *pszError, size_t cbError) 856 { 857 int rc = vboxExtPackValidateMemberName(pszName, pszError, cbError); 858 if (RT_SUCCESS(rc)) 859 { 860 RTFSOBJINFO ObjInfo; 861 rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING); 862 if (RT_SUCCESS(rc)) 863 { 864 if (!RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode)) 865 rc = vboxExtPackReturnError(VERR_NOT_A_DIRECTORY, pszError, cbError, 866 "The alleged directory '%s' has a mode mask saying differently (%RTfmode)", 867 pszName, ObjInfo.Attr.fMode); 868 } 869 else 870 vboxExtPackSetError(pszError, cbError, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc); 871 } 872 return rc; 873 } 874 875 /** 876 * Validates a member of an extension pack. 877 * 878 * @returns VBox status code, failures with message. 879 * @param pszName The name of the directory. 880 * @param enmType The object type. 881 * @param hVfsObj The VFS object. 882 * @param pszError Where to store an error message on failure. 883 * @param cbError The size of the buffer @a pszError points to. 884 */ 885 int VBoxExtPackValidateMember(const char *pszName, RTVFSOBJTYPE enmType, RTVFSOBJ hVfsObj, char *pszError, size_t cbError) 886 { 887 Assert(cbError > 0); 888 *pszError = '\0'; 889 890 int rc; 891 if ( enmType == RTVFSOBJTYPE_FILE 892 || enmType == RTVFSOBJTYPE_IO_STREAM) 893 rc = vboxExtPackValidateMemberFile(pszName, hVfsObj, pszError, cbError); 894 else if ( enmType == RTVFSOBJTYPE_DIR 895 || enmType == RTVFSOBJTYPE_BASE) 896 rc = vboxExtPackValidateMemberDir(pszName, hVfsObj, pszError, cbError); 897 else 898 rc = vboxExtPackReturnError(VERR_UNEXPECTED_FS_OBJ_TYPE, pszError, cbError, 899 "'%s' is not a file or directory (enmType=%d)", pszName, enmType); 900 return rc; 901 } 902 903 904 /** 905 * Rewinds the tarball file handle and creates a gunzip | tar chain that 906 * results in a filesystem stream. 907 * 908 * @returns VBox status code, failures with message. 909 * @param hTarballFile The handle to the tarball file. 910 * @param pszError Where to store an error message on failure. 911 * @param cbError The size of the buffer @a pszError points to. 912 * @param phTarFss Where to return the filesystem stream handle. 913 */ 914 int VBoxExtPackOpenTarFss(RTFILE hTarballFile, char *pszError, size_t cbError, PRTVFSFSSTREAM phTarFss) 915 { 916 Assert(cbError > 0); 917 *pszError = '\0'; 918 *phTarFss = NIL_RTVFSFSSTREAM; 919 920 /* 921 * Rewind the file and set up a VFS chain for it. 922 */ 923 int rc = RTFileSeek(hTarballFile, 0, RTFILE_SEEK_BEGIN, NULL); 924 if (RT_FAILURE(rc)) 925 return vboxExtPackReturnError(rc, pszError, cbError, "Failed seeking to the start of the tarball: %Rrc", rc); 926 927 RTVFSIOSTREAM hTarballIos; 928 rc = RTVfsIoStrmFromRTFile(hTarballFile, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN, true /*fLeaveOpen*/, 929 &hTarballIos); 930 if (RT_FAILURE(rc)) 931 return vboxExtPackReturnError(rc, pszError, cbError, "RTVfsIoStrmFromRTFile failed: %Rrc", rc); 932 933 RTVFSIOSTREAM hGunzipIos; 934 rc = RTZipGzipDecompressIoStream(hTarballIos, 0 /*fFlags*/, &hGunzipIos); 935 if (RT_SUCCESS(rc)) 936 { 937 RTVFSFSSTREAM hTarFss; 938 rc = RTZipTarFsStreamFromIoStream(hGunzipIos, 0 /*fFlags*/, &hTarFss); 939 if (RT_SUCCESS(rc)) 940 { 941 RTVfsIoStrmRelease(hGunzipIos); 942 RTVfsIoStrmRelease(hTarballIos); 943 *phTarFss = hTarFss; 944 return VINF_SUCCESS; 945 } 946 vboxExtPackSetError(pszError, cbError, "RTZipTarFsStreamFromIoStream failed: %Rrc", rc); 947 RTVfsIoStrmRelease(hGunzipIos); 948 } 949 else 950 vboxExtPackSetError(pszError, cbError, "RTZipGzipDecompressIoStream failed: %Rrc", rc); 951 RTVfsIoStrmRelease(hTarballIos); 952 return rc; 953 } 954 955 956 /** 957 * Validates the extension pack tarball prior to unpacking. 958 * 959 * Operations performed: 960 * - Mandatory files. 961 * - Manifest check. 962 * - Manifest seal check. 963 * - XML check, match name. 964 * 965 * @returns VBox status code, failures with message. 966 * @param hTarballFile The handle to open the @a pszTarball file. 967 * @param pszExtPackName The name of the extension pack name. NULL if 968 * the name is not fixed. 969 * @param pszTarball The name of the tarball in case we have to 970 * complain about something. 971 * @param pszError Where to store an error message on failure. 972 * @param cbError The size of the buffer @a pszError points to. 973 * @param phValidManifest Where to optionally return the handle to fully 974 * validated the manifest for the extension pack. 975 * This includes all files. 976 * @param phXmlFile Where to optionally return the memorized XML 977 * file. 978 * 979 * @todo This function is a bit too long and should be split up if possible. 980 */ 981 int VBoxExtPackValidateTarball(RTFILE hTarballFile, const char *pszExtPackName, const char *pszTarball, 982 char *pszError, size_t cbError, PRTMANIFEST phValidManifest, PRTVFSFILE phXmlFile) 983 { 984 /* 985 * Clear return values. 986 */ 987 if (phValidManifest) 988 *phValidManifest = NIL_RTMANIFEST; 989 if (phXmlFile) 990 *phXmlFile = NIL_RTVFSFILE; 991 Assert(cbError > 1); 992 *pszError = '\0'; 993 NOREF(pszTarball); 994 995 /* 996 * Open the tar.gz filesystem stream and set up an manifest in-memory file. 997 */ 998 RTVFSFSSTREAM hTarFss; 999 int rc = VBoxExtPackOpenTarFss(hTarballFile, pszError, cbError, &hTarFss); 1000 if (RT_FAILURE(rc)) 1001 return rc; 1002 1003 RTMANIFEST hOurManifest; 1004 rc = RTManifestCreate(0 /*fFlags*/, &hOurManifest); 1005 if (RT_SUCCESS(rc)) 1006 { 1007 /* 1008 * Process the tarball (would be nice to move this to a function). 1009 */ 1010 RTVFSFILE hXmlFile = NIL_RTVFSFILE; 1011 RTVFSFILE hManifestFile = NIL_RTVFSFILE; 1012 RTVFSFILE hSignatureFile= NIL_RTVFSFILE; 1013 for (;;) 1014 { 1015 /* 1016 * Get the next stream object. 1017 */ 1018 char *pszName; 1019 RTVFSOBJ hVfsObj; 1020 RTVFSOBJTYPE enmType; 1021 rc = RTVfsFsStrmNext(hTarFss, &pszName, &enmType, &hVfsObj); 1022 if (RT_FAILURE(rc)) 1023 { 1024 if (rc != VERR_EOF) 1025 vboxExtPackSetError(pszError, cbError, "RTVfsFsStrmNext failed: %Rrc", rc); 1026 else 1027 rc = VINF_SUCCESS; 1028 break; 1029 } 1030 const char *pszAdjName = pszName[0] == '.' && pszName[1] == '/' ? &pszName[2] : pszName; 1031 1032 /* 1033 * Check the type & name validity. 1034 * 1035 * N.B. We will always reach the end of the loop before breaking on 1036 * failure - cleanup reasons. 1037 */ 1038 rc = VBoxExtPackValidateMember(pszName, enmType, hVfsObj, pszError, cbError); 1039 if (RT_SUCCESS(rc)) 1040 { 1041 /* 1042 * Check if this is one of the standard files. 1043 */ 1044 PRTVFSFILE phVfsFile; 1045 if (!strcmp(pszAdjName, VBOX_EXTPACK_DESCRIPTION_NAME)) 1046 phVfsFile = &hXmlFile; 1047 else if (!strcmp(pszAdjName, VBOX_EXTPACK_MANIFEST_NAME)) 1048 phVfsFile = &hManifestFile; 1049 else if (!strcmp(pszAdjName, VBOX_EXTPACK_SIGNATURE_NAME)) 1050 phVfsFile = &hSignatureFile; 1051 else 1052 phVfsFile = NULL; 1053 if (phVfsFile) 1054 { 1055 /* 1056 * Make sure it's a file and that it isn't too large. 1057 */ 1058 if (*phVfsFile != NIL_RTVFSFILE) 1059 rc = vboxExtPackReturnError(VERR_DUPLICATE, pszError, cbError, 1060 "There can only be one '%s'", pszAdjName); 1061 else if (enmType != RTVFSOBJTYPE_IO_STREAM && enmType != RTVFSOBJTYPE_FILE) 1062 rc = vboxExtPackReturnError(VERR_NOT_A_FILE, pszError, cbError, 1063 "Standard member '%s' is not a file", pszAdjName); 1064 else 1065 { 1066 RTFSOBJINFO ObjInfo; 1067 rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING); 1068 if (RT_SUCCESS(rc)) 1069 { 1070 if (!RTFS_IS_FILE(ObjInfo.Attr.fMode)) 1071 rc = vboxExtPackReturnError(VERR_NOT_A_FILE, pszError, cbError, 1072 "Standard member '%s' is not a file", pszAdjName); 1073 else if (ObjInfo.cbObject >= _1M) 1074 rc = vboxExtPackReturnError(VERR_OUT_OF_RANGE, pszError, cbError, 1075 "Standard member '%s' is too large: %'RU64 bytes (max 1 MB)", 1076 pszAdjName, (uint64_t)ObjInfo.cbObject); 1077 else 1078 { 1079 /* 1080 * Make an in memory copy of the stream. 1081 */ 1082 RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj); 1083 rc = RTVfsMemorizeIoStreamAsFile(hVfsIos, RTFILE_O_READ, phVfsFile); 1084 if (RT_SUCCESS(rc)) 1085 { 1086 /* 1087 * To simplify the code below, replace 1088 * hVfsObj with the memorized file. 1089 */ 1090 RTVfsObjRelease(hVfsObj); 1091 hVfsObj = RTVfsObjFromFile(*phVfsFile); 1092 } 1093 else 1094 vboxExtPackSetError(pszError, cbError, "RTVfsMemorizeIoStreamAsFile failed on '%s': %Rrc", pszName, rc); 1095 RTVfsIoStrmRelease(hVfsIos); 1096 } 1097 } 1098 else 1099 vboxExtPackSetError(pszError, cbError, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc); 1100 } 1101 } 1102 } 1103 1104 /* 1105 * Add any I/O stream to the manifest 1106 */ 1107 if ( RT_SUCCESS(rc) 1108 && ( enmType == RTVFSOBJTYPE_FILE 1109 || enmType == RTVFSOBJTYPE_IO_STREAM)) 1110 { 1111 RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj); 1112 rc = RTManifestEntryAddIoStream(hOurManifest, hVfsIos, pszAdjName, RTMANIFEST_ATTR_SIZE | RTMANIFEST_ATTR_SHA256); 1113 if (RT_FAILURE(rc)) 1114 vboxExtPackSetError(pszError, cbError, "RTManifestEntryAddIoStream failed on '%s': %Rrc", pszAdjName, rc); 1115 RTVfsIoStrmRelease(hVfsIos); 1116 } 1117 1118 /* 1119 * Clean up and break out on failure. 1120 */ 1121 RTVfsObjRelease(hVfsObj); 1122 RTStrFree(pszName); 1123 if (RT_FAILURE(rc)) 1124 break; 1125 } 1126 1127 /* 1128 * If we've successfully processed the tarball, verify that the 1129 * mandatory files are present. 1130 */ 1131 if (RT_SUCCESS(rc)) 1132 { 1133 if (hXmlFile == NIL_RTVFSFILE) 1134 rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_DESCRIPTION_NAME); 1135 if (hManifestFile == NIL_RTVFSFILE) 1136 rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_MANIFEST_NAME); 1137 if (hSignatureFile == NIL_RTVFSFILE) 1138 rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_SIGNATURE_NAME); 1139 } 1140 1141 /* 1142 * Check the manifest and it's signature. 1143 */ 1144 if (RT_SUCCESS(rc)) 1145 rc = vboxExtPackVerifyManifestAndSignature(hOurManifest, hManifestFile, hSignatureFile, pszError, cbError); 1146 1147 /* 1148 * Check the XML. 1149 */ 1150 if (RT_SUCCESS(rc)) 1151 rc = vboxExtPackVerifyXml(hXmlFile, pszExtPackName, pszError, cbError); 1152 1153 /* 1154 * Returns objects. 1155 */ 1156 if (RT_SUCCESS(rc)) 1157 { 1158 if (phValidManifest) 1159 { 1160 RTManifestRetain(hOurManifest); 1161 *phValidManifest = hOurManifest; 1162 } 1163 if (phXmlFile) 1164 { 1165 RTVfsFileRetain(hXmlFile); 1166 *phXmlFile = hXmlFile; 1167 } 1168 } 1169 1170 /* 1171 * Release our object references. 1172 */ 1173 RTManifestRelease(hOurManifest); 1174 RTVfsFileRelease(hXmlFile); 1175 RTVfsFileRelease(hManifestFile); 1176 RTVfsFileRelease(hSignatureFile); 1177 } 1178 else 1179 vboxExtPackSetError(pszError, cbError, "RTManifestCreate failed: %Rrc", rc); 1180 RTVfsFsStrmRelease(hTarFss); 1181 1182 return rc; 1183 } 1184 -
trunk/src/VBox/Main/VBoxExtPackHelperApp.cpp
r34762 r34787 78 78 #endif 79 79 80 /** The maximum entry name length.81 * Play short and safe. */82 #define VBOX_EXTPACK_MAX_ENTRY_NAME_LENGTH 12883 80 84 81 … … 202 199 203 200 /** 204 * Rewinds the tarball file handle and creates a gunzip | tar chain that 205 * results in a filesystem stream. 201 * Wrapper around VBoxExtPackOpenTarFss. 206 202 * 207 203 * @returns success or failure, message displayed on failure. … … 211 207 static RTEXITCODE OpenTarFss(RTFILE hTarballFile, PRTVFSFSSTREAM phTarFss) 212 208 { 213 /* 214 * Rewind the file and set up a VFS chain for it. 215 */ 216 int rc = RTFileSeek(hTarballFile, 0, RTFILE_SEEK_BEGIN, NULL); 217 if (RT_FAILURE(rc)) 218 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Failed seeking to the start of the tarball: %Rrc\n", rc); 219 220 RTVFSIOSTREAM hTarballIos; 221 rc = RTVfsIoStrmFromRTFile(hTarballFile, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN, true /*fLeaveOpen*/, 222 &hTarballIos); 223 if (RT_FAILURE(rc)) 224 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsIoStrmFromRTFile failed: %Rrc\n", rc); 225 226 RTVFSIOSTREAM hGunzipIos; 227 rc = RTZipGzipDecompressIoStream(hTarballIos, 0 /*fFlags*/, &hGunzipIos); 228 if (RT_SUCCESS(rc)) 229 { 230 RTVFSFSSTREAM hTarFss; 231 rc = RTZipTarFsStreamFromIoStream(hGunzipIos, 0 /*fFlags*/, &hTarFss); 232 if (RT_SUCCESS(rc)) 233 { 234 RTVfsIoStrmRelease(hGunzipIos); 235 RTVfsIoStrmRelease(hTarballIos); 236 *phTarFss = hTarFss; 237 return RTEXITCODE_SUCCESS; 238 } 239 RTMsgError("RTZipTarFsStreamFromIoStream failed: %Rrc\n", rc); 240 RTVfsIoStrmRelease(hGunzipIos); 241 } 242 else 243 RTMsgError("RTZipGzipDecompressIoStream failed: %Rrc\n", rc); 244 RTVfsIoStrmRelease(hTarballIos); 245 return RTEXITCODE_FAILURE; 209 char szError[8192]; 210 int rc = VBoxExtPackOpenTarFss(hTarballFile, szError, sizeof(szError), phTarFss); 211 if (RT_FAILURE(rc)) 212 { 213 Assert(szError[0]); 214 return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s", szError); 215 } 216 Assert(!szError[0]); 217 return RTEXITCODE_SUCCESS; 246 218 } 247 219 … … 273 245 274 246 /** 275 * Verifies the manifest and its signature. 276 * 277 * @returns Program exit code, failure with message. 278 * @param hManifestFile The xml from the extension pack. 279 * @param pszExtPackName The expected extension pack name. 280 */ 281 static RTEXITCODE VerifyXml(RTVFSFILE hXmlFile, const char *pszExtPackName) 282 { 283 /** @todo implement XML verification. */ 284 return RTEXITCODE_SUCCESS; 285 } 286 287 288 /** 289 * Verifies the manifest and its signature. 290 * 291 * @returns Program exit code, failure with message. 292 * @param hOurManifest The manifest we compiled. 293 * @param hManifestFile The manifest file in the extension pack. 294 * @param hSignatureFile The manifest signature file. 295 */ 296 static RTEXITCODE VerifyManifestAndSignature(RTMANIFEST hOurManifest, RTVFSFILE hManifestFile, RTVFSFILE hSignatureFile) 297 { 298 /* 299 * Read the manifest from the extension pack. 300 */ 301 int rc = RTVfsFileSeek(hManifestFile, 0, RTFILE_SEEK_BEGIN, NULL); 302 if (RT_FAILURE(rc)) 303 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsFileSeek failed: %Rrc", rc); 304 305 RTMANIFEST hTheirManifest; 306 rc = RTManifestCreate(0 /*fFlags*/, &hTheirManifest); 307 if (RT_FAILURE(rc)) 308 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTManifestCreate failed: %Rrc", rc); 309 310 RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hManifestFile); 311 rc = RTManifestReadStandard(hTheirManifest, hVfsIos); 312 RTVfsIoStrmRelease(hVfsIos); 313 if (RT_SUCCESS(rc)) 314 { 315 /* 316 * Compare the manifests. 317 */ 318 static const char *s_apszIgnoreEntries[] = 319 { 320 VBOX_EXTPACK_MANIFEST_NAME, 321 VBOX_EXTPACK_SIGNATURE_NAME, 322 "./" VBOX_EXTPACK_MANIFEST_NAME, 323 "./" VBOX_EXTPACK_SIGNATURE_NAME, 324 NULL 325 }; 326 char szError[RTPATH_MAX]; 327 rc = RTManifestEqualsEx(hOurManifest, hTheirManifest, &s_apszIgnoreEntries[0], NULL, 328 RTMANIFEST_EQUALS_IGN_MISSING_ATTRS /*fFlags*/, 329 szError, sizeof(szError)); 330 if (RT_SUCCESS(rc)) 331 { 332 /* 333 * Validate the manifest file signature. 334 */ 335 /** @todo implement signature stuff */ 336 337 } 338 else if (rc == VERR_NOT_EQUAL && szError[0]) 339 RTMsgError("Manifest mismatch: %s", szError); 340 else 341 RTMsgError("RTManifestEqualsEx failed: %Rrc", rc); 342 #if 0 343 RTVFSIOSTREAM hVfsIosStdOut = NIL_RTVFSIOSTREAM; 344 RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, RTFILE_O_WRITE, true, &hVfsIosStdOut); 345 RTVfsIoStrmWrite(hVfsIosStdOut, "Our:\n", sizeof("Our:\n") - 1, true, NULL); 346 RTManifestWriteStandard(hOurManifest, hVfsIosStdOut); 347 RTVfsIoStrmWrite(hVfsIosStdOut, "Their:\n", sizeof("Their:\n") - 1, true, NULL); 348 RTManifestWriteStandard(hTheirManifest, hVfsIosStdOut); 349 #endif 350 } 351 else 352 RTMsgError("Error parsing '%s': %Rrc", VBOX_EXTPACK_MANIFEST_NAME, rc); 353 354 RTManifestRelease(hTheirManifest); 355 return RT_SUCCESS(rc) ? RTEXITCODE_SUCCESS : RTEXITCODE_FAILURE; 356 } 357 358 359 /** 360 * Validates a name in an extension pack. 361 * 362 * We restrict the charset to try make sure the extension pack can be unpacked 363 * on all file systems. 364 * 365 * @returns Program exit code, failure with message. 366 * @param pszName The name to validate. 367 */ 368 static RTEXITCODE ValidateNameInExtPack(const char *pszName) 369 { 370 if (RTPathStartsWithRoot(pszName)) 371 return RTMsgErrorExit(RTEXITCODE_FAILURE, "'%s': starts with root spec", pszName); 372 373 const char *pszErr = NULL; 374 const char *psz = pszName; 375 int ch; 376 while ((ch = *psz) != '\0') 377 { 378 /* Character set restrictions. */ 379 if (ch < 0 || ch >= 128) 380 { 381 pszErr = "Only 7-bit ASCII allowed"; 382 break; 383 } 384 if (ch <= 31 || ch == 127) 385 { 386 pszErr = "No control characters are not allowed"; 387 break; 388 } 389 if (ch == '\\') 390 { 391 pszErr = "Only backward slashes are not allowed"; 392 break; 393 } 394 if (strchr("'\":;*?|[]<>(){}", ch)) 395 { 396 pszErr = "The characters ', \", :, ;, *, ?, |, [, ], <, >, (, ), { and } are not allowed"; 397 break; 398 } 399 400 /* Take the simple way out and ban all ".." sequences. */ 401 if ( ch == '.' 402 && psz[1] == '.') 403 { 404 pszErr = "Double dot sequence are not allowed"; 405 break; 406 } 407 408 /* Keep the tree shallow or the hardening checks will fail. */ 409 if (psz - pszName > VBOX_EXTPACK_MAX_ENTRY_NAME_LENGTH) 410 { 411 pszErr = "Too long"; 412 break; 413 } 414 415 /* advance */ 416 psz++; 417 } 418 419 if (pszErr) 420 return RTMsgErrorExit(RTEXITCODE_FAILURE, "Bad member name '%s' (pos %zu): %s", pszName, (size_t)(psz - pszName), pszErr); 421 return RTEXITCODE_SUCCESS; 422 } 423 424 425 /** 426 * Validates a file in an extension pack. 427 * 428 * @returns Program exit code, failure with message. 429 * @param pszName The name of the file. 430 * @param hVfsObj The VFS object. 431 */ 432 static RTEXITCODE ValidateFileInExtPack(const char *pszName, RTVFSOBJ hVfsObj) 433 { 434 RTEXITCODE rcExit = ValidateNameInExtPack(pszName); 435 if (rcExit == RTEXITCODE_SUCCESS) 436 { 437 RTFSOBJINFO ObjInfo; 438 int rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING); 439 if (RT_SUCCESS(rc)) 440 { 441 if (ObjInfo.cbObject >= 9*_1G64) 442 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "'%s': too large (%'RU64 bytes)", 443 pszName, (uint64_t)ObjInfo.cbObject); 444 if (!RTFS_IS_FILE(ObjInfo.Attr.fMode)) 445 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, 446 "The alleged file '%s' has a mode mask saying differently (%RTfmode)", 447 pszName, ObjInfo.Attr.fMode); 448 } 449 else 450 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc); 451 } 452 return rcExit; 453 } 454 455 456 /** 457 * Validates a directory in an extension pack. 458 * 459 * @returns Program exit code, failure with message. 460 * @param pszName The name of the directory. 461 * @param hVfsObj The VFS object. 462 */ 463 static RTEXITCODE ValidateDirInExtPack(const char *pszName, RTVFSOBJ hVfsObj) 464 { 465 RTEXITCODE rcExit = ValidateNameInExtPack(pszName); 466 if (rcExit == RTEXITCODE_SUCCESS) 467 { 468 RTFSOBJINFO ObjInfo; 469 int rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING); 470 if (RT_SUCCESS(rc)) 471 { 472 if (!RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode)) 473 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, 474 "The alleged directory '%s' has a mode mask saying differently (%RTfmode)", 475 pszName, ObjInfo.Attr.fMode); 476 } 477 else 478 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc); 479 } 480 return rcExit; 481 } 482 483 484 /** 485 * Validates a member of an extension pack. 247 * Wrapper around VBoxExtPackValidateMember. 486 248 * 487 249 * @returns Program exit code, failure with message. … … 492 254 static RTEXITCODE ValidateMemberOfExtPack(const char *pszName, RTVFSOBJTYPE enmType, RTVFSOBJ hVfsObj) 493 255 { 494 RTEXITCODE rcExit; 495 if ( enmType == RTVFSOBJTYPE_FILE 496 || enmType == RTVFSOBJTYPE_IO_STREAM) 497 rcExit = ValidateFileInExtPack(pszName, hVfsObj); 498 else if ( enmType == RTVFSOBJTYPE_DIR 499 || enmType == RTVFSOBJTYPE_BASE) 500 rcExit = ValidateDirInExtPack(pszName, hVfsObj); 501 else 502 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "'%s' is not a file or directory (enmType=%d)", pszName, enmType); 503 return rcExit; 256 char szError[8192]; 257 int rc = VBoxExtPackValidateMember(pszName, enmType, hVfsObj, szError, sizeof(szError)); 258 if (RT_FAILURE(rc)) 259 { 260 Assert(szError[0]); 261 return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s", szError); 262 } 263 Assert(!szError[0]); 264 return RTEXITCODE_SUCCESS; 504 265 } 505 266 … … 657 418 */ 658 419 char szDstPath[RTPATH_MAX]; 659 int rc = RTPathAbs(pszDirDst, szDstPath, sizeof(szDstPath) - VBOX_EXTPACK_MAX_ ENTRY_NAME_LENGTH - 2);420 int rc = RTPathAbs(pszDirDst, szDstPath, sizeof(szDstPath) - VBOX_EXTPACK_MAX_MEMBER_NAME_LENGTH - 2); 660 421 if (RT_FAILURE(rc)) 661 422 return RTMsgErrorExit(RTEXITCODE_FAILURE, "RTPathAbs('%s',,) failed: %Rrc", pszDirDst, rc); … … 763 524 764 525 /** 765 * Validates the extension pack tarball prior to unpacking. 766 * 767 * Operations performed: 768 * - Mandatory files. 769 * - Manifest check. 770 * - Manifest seal check. 771 * - XML check, match name. 526 * Wrapper around VBoxExtPackValidateTarball. 772 527 * 773 528 * @returns The program exit code. … … 779 534 * the manifest for the extension pack. This 780 535 * includes all files. 781 *782 * @todo This function is a bit too long and should be split up if possible.783 536 */ 784 537 static RTEXITCODE ValidateExtPackTarball(RTFILE hTarballFile, const char *pszExtPackName, const char *pszTarball, … … 788 541 RTMsgInfo("Validating extension pack '%s' ('%s')...", pszTarball, pszExtPackName); 789 542 790 /* 791 * Open the tar.gz filesystem stream and set up an manifest in-memory file. 792 */ 793 RTVFSFSSTREAM hTarFss; 794 RTEXITCODE rcExit = OpenTarFss(hTarballFile, &hTarFss); 795 if (rcExit != RTEXITCODE_SUCCESS) 796 return rcExit; 797 798 RTMANIFEST hOurManifest; 799 int rc = RTManifestCreate(0 /*fFlags*/, &hOurManifest); 800 if (RT_SUCCESS(rc)) 801 { 802 /* 803 * Process the tarball (would be nice to move this to a function). 804 */ 805 RTVFSFILE hXmlFile = NIL_RTVFSFILE; 806 RTVFSFILE hManifestFile = NIL_RTVFSFILE; 807 RTVFSFILE hSignatureFile= NIL_RTVFSFILE; 808 for (;;) 809 { 810 /* 811 * Get the next stream object. 812 */ 813 char *pszName; 814 RTVFSOBJ hVfsObj; 815 RTVFSOBJTYPE enmType; 816 rc = RTVfsFsStrmNext(hTarFss, &pszName, &enmType, &hVfsObj); 817 if (RT_FAILURE(rc)) 818 { 819 if (rc != VERR_EOF) 820 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsFsStrmNext failed: %Rrc", rc); 821 break; 822 } 823 const char *pszAdjName = pszName[0] == '.' && pszName[1] == '/' ? &pszName[2] : pszName; 824 825 /* 826 * Check the type & name validity. 827 */ 828 rcExit = ValidateMemberOfExtPack(pszName, enmType, hVfsObj); 829 if (rcExit == RTEXITCODE_SUCCESS) 830 { 831 /* 832 * Check if this is one of the standard files. 833 */ 834 PRTVFSFILE phVfsFile; 835 if (!strcmp(pszAdjName, VBOX_EXTPACK_DESCRIPTION_NAME)) 836 phVfsFile = &hXmlFile; 837 else if (!strcmp(pszAdjName, VBOX_EXTPACK_MANIFEST_NAME)) 838 phVfsFile = &hManifestFile; 839 else if (!strcmp(pszAdjName, VBOX_EXTPACK_SIGNATURE_NAME)) 840 phVfsFile = &hSignatureFile; 841 else 842 phVfsFile = NULL; 843 if (phVfsFile) 844 { 845 /* 846 * Make sure it's a file and that it isn't too large. 847 */ 848 if (*phVfsFile != NIL_RTVFSFILE) 849 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "There can only be one '%s'", pszAdjName); 850 else if (enmType != RTVFSOBJTYPE_IO_STREAM && enmType != RTVFSOBJTYPE_FILE) 851 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Standard member '%s' is not a file", pszAdjName); 852 else 853 { 854 RTFSOBJINFO ObjInfo; 855 rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING); 856 if (RT_SUCCESS(rc)) 857 { 858 if (!RTFS_IS_FILE(ObjInfo.Attr.fMode)) 859 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Standard member '%s' is not a file", pszAdjName); 860 else if (ObjInfo.cbObject >= _1M) 861 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, 862 "Standard member '%s' is too large: %'RU64 bytes (max 1 MB)", 863 pszAdjName, (uint64_t)ObjInfo.cbObject); 864 else 865 { 866 /* 867 * Make an in memory copy of the stream. 868 */ 869 RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj); 870 rc = RTVfsMemorizeIoStreamAsFile(hVfsIos, RTFILE_O_READ, phVfsFile); 871 if (RT_SUCCESS(rc)) 872 { 873 /* 874 * To simplify the code below, replace 875 * hVfsObj with the memorized file. 876 */ 877 RTVfsObjRelease(hVfsObj); 878 hVfsObj = RTVfsObjFromFile(*phVfsFile); 879 } 880 else 881 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, 882 "RTVfsMemorizeIoStreamAsFile failed on '%s': %Rrc", pszName, rc); 883 RTVfsIoStrmRelease(hVfsIos); 884 } 885 } 886 else 887 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc); 888 } 889 } 890 } 891 892 /* 893 * Add any I/O stream to the manifest 894 */ 895 if ( rcExit == RTEXITCODE_SUCCESS 896 && ( enmType == RTVFSOBJTYPE_FILE 897 || enmType == RTVFSOBJTYPE_IO_STREAM)) 898 { 899 RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj); 900 rc = RTManifestEntryAddIoStream(hOurManifest, hVfsIos, pszAdjName, RTMANIFEST_ATTR_SIZE | RTMANIFEST_ATTR_SHA256); 901 if (RT_FAILURE(rc)) 902 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "RTManifestEntryAddIoStream failed on '%s': %Rrc", pszAdjName, rc); 903 RTVfsIoStrmRelease(hVfsIos); 904 } 905 906 /* 907 * Clean up and break out on failure. 908 */ 909 RTVfsObjRelease(hVfsObj); 910 RTStrFree(pszName); 911 if (rcExit != RTEXITCODE_SUCCESS) 912 break; 913 } 914 915 /* 916 * If we've successfully processed the tarball, verify that the 917 * mandatory files are present. 918 */ 919 if (rcExit == RTEXITCODE_SUCCESS) 920 { 921 if (hXmlFile == NIL_RTVFSFILE) 922 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Mandator file '%s' is missing", VBOX_EXTPACK_DESCRIPTION_NAME); 923 if (hManifestFile == NIL_RTVFSFILE) 924 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Mandator file '%s' is missing", VBOX_EXTPACK_MANIFEST_NAME); 925 if (hSignatureFile == NIL_RTVFSFILE) 926 rcExit = RTMsgErrorExit(RTEXITCODE_FAILURE, "Mandator file '%s' is missing", VBOX_EXTPACK_SIGNATURE_NAME); 927 } 928 929 /* 930 * Check the manifest and it's signature. 931 */ 932 if (rcExit == RTEXITCODE_SUCCESS) 933 rcExit = VerifyManifestAndSignature(hOurManifest, hManifestFile, hSignatureFile); 934 935 /* 936 * Check the XML. 937 */ 938 if (rcExit == RTEXITCODE_SUCCESS) 939 rcExit = VerifyXml(hXmlFile, pszExtPackName); 940 941 /* 942 * Release objects and stuff. 943 */ 944 if (rcExit == RTEXITCODE_SUCCESS) 945 *phValidManifest = hOurManifest; 946 else 947 RTManifestRelease(hOurManifest); 948 949 RTVfsFileRelease(hXmlFile); 950 RTVfsFileRelease(hManifestFile); 951 RTVfsFileRelease(hSignatureFile); 952 } 953 RTVfsFsStrmRelease(hTarFss); 954 955 return rcExit; 543 char szError[8192]; 544 int rc = VBoxExtPackValidateTarball(hTarballFile, pszExtPackName, pszTarball, 545 szError, sizeof(szError), phValidManifest, NULL /*phXmlFile*/); 546 if (RT_FAILURE(rc)) 547 { 548 Assert(szError[0]); 549 return RTMsgErrorExit(RTEXITCODE_FAILURE, "%s", szError); 550 } 551 Assert(!szError[0]); 552 return RTEXITCODE_SUCCESS; 956 553 } 957 554 -
trunk/src/VBox/Main/idl/VirtualBox.xidl
r34714 r34787 14432 14432 <interface 14433 14433 name="IExtPackManager" extends="$unknown" 14434 uuid=" 8104df65-74d6-4e33-b374-50aa062b4afd"14434 uuid="70d808a9-176f-4d45-adad-7c509b8309b3" 14435 14435 wsmap="suppress" 14436 14436 > … … 14474 14474 <param name="file" type="IExtPackFile" dir="return"> 14475 14475 <desc>The interface of the extension pack file object.</desc> 14476 </param>14477 </method>14478 14479 <method name="install">14480 <desc>14481 Please use openExtPackFile + IExtPackFile::install instead of this14482 interface. This will be removed later in the beta cycle.14483 </desc>14484 <param name="path" type="wstring" dir="in">14485 <desc>The path of the extension pack tarball.</desc>14486 </param>14487 <param name="name" type="wstring" dir="return">14488 <desc>The name of the installed extension pack.</desc>14489 14476 </param> 14490 14477 </method> -
trunk/src/VBox/Main/include/ExtPackManagerImpl.h
r34714 r34787 46 46 HRESULT FinalConstruct(); 47 47 void FinalRelease(); 48 HRESULT initWithFile(const char *a_pszFile );48 HRESULT initWithFile(const char *a_pszFile, class ExtPackManager *a_pExtPackMgr); 49 49 void uninit(); 50 RTMEMEF_NEW_AND_DELETE_OPERATORS(); 50 51 /** @} */ 51 52 … … 67 68 STDMETHOD(Install)(void); 68 69 /** @} */ 70 71 private: 72 /** @name Misc init helpers 73 * @{ */ 74 HRESULT initFailed(const char *a_pszWhyFmt, ...); 75 /** @} */ 69 76 70 77 private: … … 102 109 HRESULT initWithDir(VBOXEXTPACKCTX a_enmContext, const char *a_pszName, const char *a_pszDir); 103 110 void uninit(); 111 RTMEMEF_NEW_AND_DELETE_OPERATORS(); 104 112 /** @} */ 105 113 … … 188 196 VBOXEXTPACKCTX a_enmContext); 189 197 void uninit(); 198 RTMEMEF_NEW_AND_DELETE_OPERATORS(); 190 199 /** @} */ 191 200 … … 195 204 STDMETHOD(Find)(IN_BSTR a_bstrName, IExtPack **a_pExtPack); 196 205 STDMETHOD(OpenExtPackFile)(IN_BSTR a_bstrTarball, IExtPackFile **a_ppExtPackFile); 197 STDMETHOD(Install)(IN_BSTR a_bstrTarball, BSTR *a_pbstrName);198 206 STDMETHOD(Uninstall)(IN_BSTR a_bstrName, BOOL a_fForcedRemoval); 199 207 STDMETHOD(Cleanup)(void); … … 203 211 /** @name Internal interfaces used by other Main classes. 204 212 * @{ */ 205 void processDropZone(void); 213 HRESULT doInstall(ExtPackFile *a_pExtPackFile); 214 /*void processDropZone(void);*/ 206 215 void callAllVirtualBoxReadyHooks(void); 207 216 void callAllConsoleReadyHooks(IConsole *a_pConsole); -
trunk/src/VBox/Main/include/ExtPackUtil.h
r34579 r34787 21 21 #include <iprt/cpp/ministring.h> 22 22 #include <iprt/fs.h> 23 #include <iprt/vfs.h> 23 24 24 25 … … 47 48 * certificates are installed. Relative to RTPathAppPrivateNoArch. */ 48 49 #define VBOX_EXTPACK_CERT_DIR "ExtPackCertificates" 50 51 /** The maximum entry name length. 52 * Play short and safe. */ 53 #define VBOX_EXTPACK_MAX_MEMBER_NAME_LENGTH 128 49 54 50 55 … … 98 103 99 104 iprt::MiniString *VBoxExtPackLoadDesc(const char *a_pszDir, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo); 105 iprt::MiniString *VBoxExtPackLoadDescFromVfsFile(RTVFSFILE hVfsFile, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo); 100 106 iprt::MiniString *VBoxExtPackExtractNameFromTarballPath(const char *pszTarball); 101 107 void VBoxExtPackFreeDesc(PVBOXEXTPACKDESC a_pExtPackDesc); … … 108 114 bool VBoxExtPackIsValidModuleString(const char *pszModule); 109 115 116 int VBoxExtPackValidateMember(const char *pszName, RTVFSOBJTYPE enmType, RTVFSOBJ hVfsObj, char *pszError, size_t cbError); 117 int VBoxExtPackOpenTarFss(RTFILE hTarballFile, char *pszError, size_t cbError, PRTVFSFSSTREAM phTarFss); 118 int VBoxExtPackValidateTarball(RTFILE hTarballFile, const char *pszExtPackName, const char *pszTarball, 119 char *pszError, size_t cbError, PRTMANIFEST phValidManifest, PRTVFSFILE phXmlFile); 120 110 121 111 122 #endif
Note:
See TracChangeset
for help on using the changeset viewer.