VirtualBox

source: vbox/trunk/src/VBox/Main/src-all/ExtPackManagerImpl.cpp@ 107868

最後變更 在這個檔案從107868是 107726,由 vboxsync 提交於 2 月 前

Main/src-all/ExtPackManagerImpl.cpp: Add IPRT status code assertion, bugref:3409

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 133.5 KB
 
1/* $Id: ExtPackManagerImpl.cpp 107726 2025-01-13 20:45:29Z vboxsync $ */
2/** @file
3 * VirtualBox Main - interface for Extension Packs, VBoxSVC & VBoxC.
4 */
5
6/*
7 * Copyright (C) 2010-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.alldomusa.eu.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * SPDX-License-Identifier: GPL-3.0-only
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include "ExtPackManagerImpl.h"
33#include "CloudProviderManagerImpl.h"
34#include "ExtPackUtil.h"
35#include "ThreadTask.h"
36
37#include <iprt/buildconfig.h>
38#include <iprt/ctype.h>
39#include <iprt/dir.h>
40#include <iprt/env.h>
41#include <iprt/file.h>
42#include <iprt/ldr.h>
43#include <iprt/locale.h>
44#include <iprt/manifest.h>
45#include <iprt/param.h>
46#include <iprt/path.h>
47#include <iprt/pipe.h>
48#include <iprt/process.h>
49#include <iprt/string.h>
50
51#include <VBox/com/array.h>
52#include <VBox/com/ErrorInfo.h>
53#include <VBox/err.h>
54#include <VBox/log.h>
55#include <VBox/sup.h>
56#include <VBox/version.h>
57
58#include <algorithm>
59
60#include "AutoCaller.h"
61#include "Global.h"
62#include "ProgressImpl.h"
63#ifdef VBOX_COM_INPROC
64# include "ConsoleImpl.h"
65#else
66# include "VirtualBoxImpl.h"
67#endif
68
69
70/*********************************************************************************************************************************
71* Defined Constants And Macros *
72*********************************************************************************************************************************/
73/** @def VBOX_EXTPACK_HELPER_NAME
74 * The name of the utility application we employ to install and uninstall the
75 * extension packs. This is a set-uid-to-root binary on unixy platforms, which
76 * is why it has to be a separate application.
77 */
78#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
79# define VBOX_EXTPACK_HELPER_NAME "VBoxExtPackHelperApp.exe"
80#else
81# define VBOX_EXTPACK_HELPER_NAME "VBoxExtPackHelperApp"
82#endif
83
84
85/*********************************************************************************************************************************
86* Structures and Typedefs *
87*********************************************************************************************************************************/
88struct ExtPackBaseData
89{
90public:
91 /** The extension pack descriptor (loaded from the XML, mostly). */
92 VBOXEXTPACKDESC Desc;
93 /** The file system object info of the XML file.
94 * This is for detecting changes and save time in refresh(). */
95 RTFSOBJINFO ObjInfoDesc;
96 /** Whether it's usable or not. */
97 bool fUsable;
98 /** Why it is unusable. */
99 Utf8Str strWhyUnusable;
100};
101
102#ifndef VBOX_COM_INPROC
103/**
104 * Private extension pack data.
105 */
106struct ExtPackFile::Data : public ExtPackBaseData
107{
108public:
109 /** The path to the tarball. */
110 Utf8Str strExtPackFile;
111 /** The SHA-256 hash of the file (as string). */
112 Utf8Str strDigest;
113 /** The file handle of the extension pack file. */
114 RTFILE hExtPackFile;
115 /** Our manifest for the tarball. */
116 RTMANIFEST hOurManifest;
117 /** Pointer to the extension pack manager. */
118 ComObjPtr<ExtPackManager> ptrExtPackMgr;
119 /** Pointer to the VirtualBox object so we can create a progress object. */
120 VirtualBox *pVirtualBox;
121
122 RTMEMEF_NEW_AND_DELETE_OPERATORS();
123};
124#endif
125
126/**
127 * Private extension pack data.
128 */
129struct ExtPack::Data : public ExtPackBaseData
130{
131public:
132 /** Where the extension pack is located. */
133 Utf8Str strExtPackPath;
134 /** The file system object info of the extension pack directory.
135 * This is for detecting changes and save time in refresh(). */
136 RTFSOBJINFO ObjInfoExtPack;
137 /** The full path to the main module. */
138 Utf8Str strMainModPath;
139 /** The file system object info of the main module.
140 * This is used to determin whether to bother try reload it. */
141 RTFSOBJINFO ObjInfoMainMod;
142 /** The module handle of the main extension pack module. */
143 RTLDRMOD hMainMod;
144
145 /** The helper callbacks for the extension pack. */
146 VBOXEXTPACKHLP Hlp;
147 /** Pointer back to the extension pack object (for Hlp methods). */
148 ExtPack *pThis;
149#ifndef VBOX_COM_INPROC
150 /** The extension pack main registration structure. */
151 PCVBOXEXTPACKREG pReg;
152#else
153 /** The extension pack main VM registration structure. */
154 PCVBOXEXTPACKVMREG pReg;
155#endif
156 /** The current context. */
157 VBOXEXTPACKCTX enmContext;
158 /** Set if we've made the pfnVirtualBoxReady or pfnConsoleReady call. */
159 bool fMadeReadyCall;
160#ifndef VBOX_COM_INPROC
161 /** Pointer to the VirtualBox object so we can create a progress object. */
162 VirtualBox *pVirtualBox;
163#endif
164#ifdef VBOX_WITH_MAIN_NLS
165 PTRCOMPONENT pTrComponent;
166#endif
167
168 RTMEMEF_NEW_AND_DELETE_OPERATORS();
169};
170
171/** List of extension packs. */
172typedef std::list< ComObjPtr<ExtPack> > ExtPackList;
173
174/**
175 * Private extension pack manager data.
176 */
177struct ExtPackManager::Data
178{
179 Data() :
180#ifndef VBOX_COM_INPROC
181 pVirtualBox(NULL),
182#endif
183 enmContext(VBOXEXTPACKCTX_INVALID)
184 , cUpdate(0)
185 {}
186
187 /** The directory where the extension packs are installed. */
188 Utf8Str strBaseDir;
189 /** The directory where the certificates this installation recognizes are
190 * stored. */
191 Utf8Str strCertificatDirPath;
192 /** The list of installed extension packs. */
193 ExtPackList llInstalledExtPacks;
194#ifndef VBOX_COM_INPROC
195 /** Pointer to the VirtualBox object, our parent. */
196 VirtualBox *pVirtualBox;
197#endif
198 /** The current context. */
199 VBOXEXTPACKCTX enmContext;
200 /** Update counter for the installed extension packs, increased in every list update. */
201 uint64_t cUpdate;
202
203 RTMEMEF_NEW_AND_DELETE_OPERATORS();
204};
205
206#ifndef VBOX_COM_INPROC
207
208/**
209 * Extension pack installation job.
210 */
211class ExtPackInstallTask : public ThreadTask
212{
213public:
214 explicit ExtPackInstallTask() : ThreadTask("ExtPackInst") { }
215 ~ExtPackInstallTask() { }
216
217 DECLARE_TRANSLATE_METHODS(ExtPackInstallTask)
218
219 void handler()
220 {
221 HRESULT hrc = ptrExtPackMgr->i_doInstall(ptrExtPackFile, fReplace, &strDisplayInfo);
222 ptrProgress->i_notifyComplete(hrc);
223 }
224
225 HRESULT Init(const ComPtr<ExtPackFile> &a_strExtPackFile, bool a_fReplace,
226 const Utf8Str &strDispInfo, const ComPtr<ExtPackManager> &a_ptrExtPackMgr)
227 {
228 ptrExtPackFile = a_strExtPackFile;
229 fReplace = a_fReplace;
230 strDisplayInfo = strDispInfo;
231 ptrExtPackMgr = a_ptrExtPackMgr;
232
233 HRESULT hrc = ptrProgress.createObject();
234 if (SUCCEEDED(hrc))
235 {
236 Bstr bstrDescription(tr("Installing extension pack"));
237 hrc = ptrProgress->init(ptrExtPackFile->m->pVirtualBox,
238 static_cast<IExtPackFile *>(ptrExtPackFile),
239 bstrDescription.raw(),
240 FALSE /*aCancelable*/);
241 }
242
243 return hrc;
244 }
245
246 /** Smart pointer to the progress object for this job. */
247 ComObjPtr<Progress> ptrProgress;
248private:
249 /** Smart pointer to the extension pack file. */
250 ComPtr<ExtPackFile> ptrExtPackFile;
251 /** The replace argument. */
252 bool fReplace;
253 /** The display info argument. */
254 Utf8Str strDisplayInfo;
255 /** Smart pointer to the extension manager. */
256 ComPtr<ExtPackManager> ptrExtPackMgr;
257};
258
259/**
260 * Extension pack uninstallation job.
261 */
262class ExtPackUninstallTask : public ThreadTask
263{
264public:
265 explicit ExtPackUninstallTask() : ThreadTask("ExtPackUninst") { }
266 ~ExtPackUninstallTask() { }
267 DECLARE_TRANSLATE_METHODS(ExtPackUninstallTask)
268
269 void handler()
270 {
271 HRESULT hrc = ptrExtPackMgr->i_doUninstall(&strName, fForcedRemoval, &strDisplayInfo);
272 ptrProgress->i_notifyComplete(hrc);
273 }
274
275 HRESULT Init(const ComPtr<ExtPackManager> &a_ptrExtPackMgr, const Utf8Str &a_strName,
276 bool a_fForcedRemoval, const Utf8Str &a_strDisplayInfo)
277 {
278 ptrExtPackMgr = a_ptrExtPackMgr;
279 strName = a_strName;
280 fForcedRemoval = a_fForcedRemoval;
281 strDisplayInfo = a_strDisplayInfo;
282
283 HRESULT hrc = ptrProgress.createObject();
284 if (SUCCEEDED(hrc))
285 {
286 Bstr bstrDescription(tr("Uninstalling extension pack"));
287 hrc = ptrProgress->init(ptrExtPackMgr->m->pVirtualBox,
288 static_cast<IExtPackManager *>(ptrExtPackMgr),
289 bstrDescription.raw(),
290 FALSE /*aCancelable*/);
291 }
292
293 return hrc;
294 }
295
296 /** Smart pointer to the progress object for this job. */
297 ComObjPtr<Progress> ptrProgress;
298private:
299 /** Smart pointer to the extension manager. */
300 ComPtr<ExtPackManager> ptrExtPackMgr;
301 /** The name of the extension pack. */
302 Utf8Str strName;
303 /** The replace argument. */
304 bool fForcedRemoval;
305 /** The display info argument. */
306 Utf8Str strDisplayInfo;
307};
308
309DEFINE_EMPTY_CTOR_DTOR(ExtPackFile)
310
311/**
312 * Called by ComObjPtr::createObject when creating the object.
313 *
314 * Just initialize the basic object state, do the rest in initWithDir().
315 *
316 * @returns S_OK.
317 */
318HRESULT ExtPackFile::FinalConstruct()
319{
320 m = NULL;
321 return BaseFinalConstruct();
322}
323
324/**
325 * Initializes the extension pack by reading its file.
326 *
327 * @returns COM status code.
328 * @param a_pszFile The path to the extension pack file.
329 * @param a_pszDigest The SHA-256 digest of the file. Or an empty string.
330 * @param a_pExtPackMgr Pointer to the extension pack manager.
331 * @param a_pVirtualBox Pointer to the VirtualBox object.
332 */
333HRESULT ExtPackFile::initWithFile(const char *a_pszFile, const char *a_pszDigest, ExtPackManager *a_pExtPackMgr,
334 VirtualBox *a_pVirtualBox)
335{
336 AutoInitSpan autoInitSpan(this);
337 AssertReturn(autoInitSpan.isOk(), E_FAIL);
338
339 /*
340 * Allocate + initialize our private data.
341 */
342 m = new ExtPackFile::Data;
343 VBoxExtPackInitDesc(&m->Desc);
344 RT_ZERO(m->ObjInfoDesc);
345 m->fUsable = false;
346 m->strWhyUnusable = tr("ExtPack::init failed");
347 m->strExtPackFile = a_pszFile;
348 m->strDigest = a_pszDigest;
349 m->hExtPackFile = NIL_RTFILE;
350 m->hOurManifest = NIL_RTMANIFEST;
351 m->ptrExtPackMgr = a_pExtPackMgr;
352 m->pVirtualBox = a_pVirtualBox;
353
354 RTCString *pstrTarName = VBoxExtPackExtractNameFromTarballPath(a_pszFile);
355 if (pstrTarName)
356 {
357 m->Desc.strName = *pstrTarName;
358 delete pstrTarName;
359 pstrTarName = NULL;
360 }
361
362 autoInitSpan.setSucceeded();
363
364 /*
365 * Try open the extension pack and check that it is a regular file.
366 */
367 int vrc = RTFileOpen(&m->hExtPackFile, a_pszFile,
368 RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN);
369 if (RT_FAILURE(vrc))
370 {
371 if (vrc == VERR_FILE_NOT_FOUND || vrc == VERR_PATH_NOT_FOUND)
372 return initFailed(tr("'%s' file not found"), a_pszFile);
373 return initFailed(tr("RTFileOpen('%s',,) failed with %Rrc"), a_pszFile, vrc);
374 }
375
376 RTFSOBJINFO ObjInfo;
377 vrc = RTFileQueryInfo(m->hExtPackFile, &ObjInfo, RTFSOBJATTRADD_UNIX);
378 if (RT_FAILURE(vrc))
379 return initFailed(tr("RTFileQueryInfo failed with %Rrc on '%s'"), vrc, a_pszFile);
380 if (!RTFS_IS_FILE(ObjInfo.Attr.fMode))
381 return initFailed(tr("Not a regular file: %s"), a_pszFile);
382
383 /*
384 * Validate the tarball and extract the XML file.
385 */
386 char szError[8192];
387 RTVFSFILE hXmlFile;
388 vrc = VBoxExtPackValidateTarball(m->hExtPackFile, NULL /*pszExtPackName*/, a_pszFile, a_pszDigest,
389 szError, sizeof(szError), &m->hOurManifest, &hXmlFile, &m->strDigest);
390 if (RT_FAILURE(vrc))
391 return initFailed("%s", szError);
392
393 /*
394 * Parse the XML.
395 */
396 RTCString strSavedName(m->Desc.strName);
397 RTCString *pStrLoadErr = VBoxExtPackLoadDescFromVfsFile(hXmlFile, &m->Desc, &m->ObjInfoDesc);
398 RTVfsFileRelease(hXmlFile);
399 if (pStrLoadErr != NULL)
400 {
401 m->strWhyUnusable.printf(tr("Failed to the xml file: %s"), pStrLoadErr->c_str());
402 m->Desc.strName = strSavedName;
403 delete pStrLoadErr;
404 return S_OK;
405 }
406
407 /*
408 * Match the tarball name with the name from the XML.
409 */
410 /** @todo drop this restriction after the old install interface is
411 * dropped. */
412 if (!strSavedName.equalsIgnoreCase(m->Desc.strName))
413 return initFailed(tr("Extension pack name mismatch between the downloaded file and the XML inside it (xml='%s' file='%s')"),
414 m->Desc.strName.c_str(), strSavedName.c_str());
415
416
417 m->fUsable = true;
418 m->strWhyUnusable.setNull();
419 return S_OK;
420}
421
422/**
423 * Protected helper that formats the strWhyUnusable value.
424 *
425 * @returns S_OK
426 * @param a_pszWhyFmt Why it failed, format string.
427 * @param ... The format arguments.
428 */
429HRESULT ExtPackFile::initFailed(const char *a_pszWhyFmt, ...)
430{
431 va_list va;
432 va_start(va, a_pszWhyFmt);
433 m->strWhyUnusable.printfV(a_pszWhyFmt, va);
434 va_end(va);
435 return S_OK;
436}
437
438/**
439 * COM cruft.
440 */
441void ExtPackFile::FinalRelease()
442{
443 uninit();
444 BaseFinalRelease();
445}
446
447/**
448 * Do the actual cleanup.
449 */
450void ExtPackFile::uninit()
451{
452 /* Enclose the state transition Ready->InUninit->NotReady */
453 AutoUninitSpan autoUninitSpan(this);
454 if (!autoUninitSpan.uninitDone() && m != NULL)
455 {
456 VBoxExtPackFreeDesc(&m->Desc);
457 RTFileClose(m->hExtPackFile);
458 m->hExtPackFile = NIL_RTFILE;
459 RTManifestRelease(m->hOurManifest);
460 m->hOurManifest = NIL_RTMANIFEST;
461
462 delete m;
463 m = NULL;
464 }
465}
466
467HRESULT ExtPackFile::getName(com::Utf8Str &aName)
468{
469 aName = m->Desc.strName;
470 return S_OK;
471}
472
473HRESULT ExtPackFile::getDescription(com::Utf8Str &aDescription)
474{
475 aDescription = m->Desc.strDescription;
476 return S_OK;
477}
478
479HRESULT ExtPackFile::getVersion(com::Utf8Str &aVersion)
480{
481 aVersion = m->Desc.strVersion;
482 return S_OK;
483}
484
485HRESULT ExtPackFile::getEdition(com::Utf8Str &aEdition)
486{
487 aEdition = m->Desc.strEdition;
488 return S_OK;
489}
490
491HRESULT ExtPackFile::getRevision(ULONG *aRevision)
492{
493 *aRevision = m->Desc.uRevision;
494 return S_OK;
495}
496
497HRESULT ExtPackFile::getVRDEModule(com::Utf8Str &aVRDEModule)
498{
499 aVRDEModule = m->Desc.strVrdeModule;
500 return S_OK;
501}
502
503HRESULT ExtPackFile::getCryptoModule(com::Utf8Str &aCryptoModule)
504{
505 aCryptoModule = m->Desc.strCryptoModule;
506 return S_OK;
507}
508
509HRESULT ExtPackFile::getPlugIns(std::vector<ComPtr<IExtPackPlugIn> > &aPlugIns)
510{
511 /** @todo implement plug-ins. */
512#ifdef VBOX_WITH_XPCOM
513 NOREF(aPlugIns);
514#endif
515 NOREF(aPlugIns);
516 ReturnComNotImplemented();
517}
518
519HRESULT ExtPackFile::getUsable(BOOL *aUsable)
520{
521 *aUsable = m->fUsable;
522 return S_OK;
523}
524
525HRESULT ExtPackFile::getWhyUnusable(com::Utf8Str &aWhyUnusable)
526{
527 aWhyUnusable = m->strWhyUnusable;
528 return S_OK;
529}
530
531HRESULT ExtPackFile::getShowLicense(BOOL *aShowLicense)
532{
533 *aShowLicense = m->Desc.fShowLicense;
534 return S_OK;
535}
536
537HRESULT ExtPackFile::getLicense(com::Utf8Str &aLicense)
538{
539 Utf8Str strHtml("html");
540 Utf8Str str("");
541 return queryLicense(str, str, strHtml, aLicense);
542}
543
544/* Same as ExtPack::QueryLicense, should really explore the subject of base classes here... */
545HRESULT ExtPackFile::queryLicense(const com::Utf8Str &aPreferredLocale, const com::Utf8Str &aPreferredLanguage,
546 const com::Utf8Str &aFormat, com::Utf8Str &aLicenseText)
547{
548 HRESULT hrc = S_OK;
549
550 /*
551 * Validate input.
552 */
553
554 if (aPreferredLocale.length() != 2 && aPreferredLocale.length() != 0)
555 return setError(E_FAIL, tr("The preferred locale is a two character string or empty."));
556
557 if (aPreferredLanguage.length() != 2 && aPreferredLanguage.length() != 0)
558 return setError(E_FAIL, tr("The preferred language is a two character string or empty."));
559
560 if ( !aFormat.equals("html")
561 && !aFormat.equals("rtf")
562 && !aFormat.equals("txt"))
563 return setError(E_FAIL, tr("The license format can only have the values 'html', 'rtf' and 'txt'."));
564
565 /*
566 * Combine the options to form a file name before locking down anything.
567 */
568 char szName[sizeof(VBOX_EXTPACK_LICENSE_NAME_PREFIX "-de_DE.html") + 2];
569 if (aPreferredLocale.isNotEmpty() && aPreferredLanguage.isNotEmpty())
570 RTStrPrintf(szName, sizeof(szName), VBOX_EXTPACK_LICENSE_NAME_PREFIX "-%s_%s.%s",
571 aPreferredLocale.c_str(), aPreferredLanguage.c_str(), aFormat.c_str());
572 else if (aPreferredLocale.isNotEmpty())
573 RTStrPrintf(szName, sizeof(szName), VBOX_EXTPACK_LICENSE_NAME_PREFIX "-%s.%s",
574 aPreferredLocale.c_str(), aFormat.c_str());
575 else if (aPreferredLanguage.isNotEmpty())
576 RTStrPrintf(szName, sizeof(szName), VBOX_EXTPACK_LICENSE_NAME_PREFIX "-_%s.%s",
577 aPreferredLocale.c_str(), aFormat.c_str());
578 else
579 RTStrPrintf(szName, sizeof(szName), VBOX_EXTPACK_LICENSE_NAME_PREFIX ".%s",
580 aFormat.c_str());
581 /*
582 * Lock the extension pack. We need a write lock here as there must not be
583 * concurrent accesses to the tar file handle.
584 */
585 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS);
586
587 /*
588 * Do not permit this query on a pack that isn't considered usable (could
589 * be marked so because of bad license files).
590 */
591 if (!m->fUsable)
592 hrc = setError(E_FAIL, "%s", m->strWhyUnusable.c_str());
593 else
594 {
595 /*
596 * Look it up in the manifest before scanning the tarball for it
597 */
598 if (RTManifestEntryExists(m->hOurManifest, szName))
599 {
600 RTVFSFSSTREAM hTarFss;
601 char szError[8192];
602 int vrc = VBoxExtPackOpenTarFss(m->hExtPackFile, szError, sizeof(szError), &hTarFss, NULL);
603 if (RT_SUCCESS(vrc))
604 {
605 for (;;)
606 {
607 /* Get the first/next. */
608 char *pszName;
609 RTVFSOBJ hVfsObj;
610 RTVFSOBJTYPE enmType;
611 vrc = RTVfsFsStrmNext(hTarFss, &pszName, &enmType, &hVfsObj);
612 if (RT_FAILURE(vrc))
613 {
614 if (vrc != VERR_EOF)
615 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("RTVfsFsStrmNext failed: %Rrc"), vrc);
616 else
617 hrc = setErrorBoth(E_UNEXPECTED, vrc, tr("'%s' was found in the manifest but not in the tarball"), szName);
618 break;
619 }
620
621 /* Is this it? */
622 const char *pszAdjName = pszName[0] == '.' && pszName[1] == '/' ? &pszName[2] : pszName;
623 if ( !strcmp(pszAdjName, szName)
624 && ( enmType == RTVFSOBJTYPE_IO_STREAM
625 || enmType == RTVFSOBJTYPE_FILE))
626 {
627 RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj);
628 RTVfsObjRelease(hVfsObj);
629 RTStrFree(pszName);
630
631 /* Load the file into memory. */
632 RTFSOBJINFO ObjInfo;
633 vrc = RTVfsIoStrmQueryInfo(hVfsIos, &ObjInfo, RTFSOBJATTRADD_NOTHING);
634 if (RT_SUCCESS(vrc))
635 {
636 size_t cbFile = (size_t)ObjInfo.cbObject;
637 void *pvFile = RTMemAllocZ(cbFile + 1);
638 if (pvFile)
639 {
640 vrc = RTVfsIoStrmRead(hVfsIos, pvFile, cbFile, true /*fBlocking*/, NULL);
641 if (RT_SUCCESS(vrc))
642 {
643 /* try translate it into a string we can return. */
644 Bstr bstrLicense((const char *)pvFile, cbFile);
645 if (bstrLicense.isNotEmpty())
646 {
647 aLicenseText = Utf8Str(bstrLicense);
648 hrc = S_OK;
649 }
650 else
651 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc,
652 tr("The license file '%s' is empty or contains invalid UTF-8 encoding"),
653 szName);
654 }
655 else
656 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Failed to read '%s': %Rrc"), szName, vrc);
657 RTMemFree(pvFile);
658 }
659 else
660 hrc = setError(E_OUTOFMEMORY, tr("Failed to allocate %zu bytes for '%s'", "", cbFile),
661 cbFile, szName);
662 }
663 else
664 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("RTVfsIoStrmQueryInfo on '%s': %Rrc"), szName, vrc);
665 RTVfsIoStrmRelease(hVfsIos);
666 break;
667 }
668
669 /* Release current. */
670 RTVfsObjRelease(hVfsObj);
671 RTStrFree(pszName);
672 }
673 RTVfsFsStrmRelease(hTarFss);
674 }
675 else
676 hrc = setError(VBOX_E_OBJECT_NOT_FOUND, "%s", szError);
677 }
678 else
679 hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("The license file '%s' was not found in '%s'"),
680 szName, m->strExtPackFile.c_str());
681 }
682 return hrc;
683}
684
685HRESULT ExtPackFile::getFilePath(com::Utf8Str &aFilePath)
686{
687
688 aFilePath = m->strExtPackFile;
689 return S_OK;
690}
691
692HRESULT ExtPackFile::install(BOOL aReplace, const com::Utf8Str &aDisplayInfo, ComPtr<IProgress> &aProgress)
693{
694 HRESULT hrc;
695 if (m->fUsable)
696 {
697 ExtPackInstallTask *pTask = NULL;
698 try
699 {
700 pTask = new ExtPackInstallTask();
701 hrc = pTask->Init(this, aReplace != FALSE, aDisplayInfo, m->ptrExtPackMgr);
702 if (SUCCEEDED(hrc))
703 {
704 ComPtr<Progress> ptrProgress = pTask->ptrProgress;
705 hrc = pTask->createThreadWithType(RTTHREADTYPE_DEFAULT);
706 pTask = NULL; /* The _completely_ _undocumented_ createThread method always consumes pTask. */
707 if (SUCCEEDED(hrc))
708 hrc = ptrProgress.queryInterfaceTo(aProgress.asOutParam());
709 else
710 hrc = setError(VBOX_E_IPRT_ERROR,
711 tr("Starting thread for an extension pack installation failed with %Rrc"), hrc);
712 }
713 else
714 hrc = setError(VBOX_E_IPRT_ERROR,
715 tr("Looks like creating a progress object for ExtraPackInstallTask object failed"));
716 }
717 catch (std::bad_alloc &)
718 {
719 hrc = E_OUTOFMEMORY;
720 }
721 catch (HRESULT hrcXcpt)
722 {
723 LogFlowThisFunc(("Exception was caught in the function ExtPackFile::install() \n"));
724 hrc = hrcXcpt;
725 }
726 if (pTask)
727 delete pTask;
728 }
729 else
730 hrc = setError(E_FAIL, "%s", m->strWhyUnusable.c_str());
731 return hrc;
732}
733
734#endif /* !VBOX_COM_INPROC */
735
736
737
738
739DEFINE_EMPTY_CTOR_DTOR(ExtPack)
740
741/**
742 * Called by ComObjPtr::createObject when creating the object.
743 *
744 * Just initialize the basic object state, do the rest in initWithDir().
745 *
746 * @returns S_OK.
747 */
748HRESULT ExtPack::FinalConstruct()
749{
750 m = NULL;
751 return BaseFinalConstruct();
752}
753
754/**
755 * Initializes the extension pack by reading its file.
756 *
757 * @returns COM status code.
758 * @param a_pVirtualBox The VirtualBox object.
759 * @param a_enmContext The context we're in.
760 * @param a_pszName The name of the extension pack. This is also the
761 * name of the subdirector under @a a_pszParentDir
762 * where the extension pack is installed.
763 * @param a_pszDir The extension pack directory name.
764 */
765HRESULT ExtPack::initWithDir(VirtualBox *a_pVirtualBox, VBOXEXTPACKCTX a_enmContext, const char *a_pszName, const char *a_pszDir)
766{
767 AutoInitSpan autoInitSpan(this);
768 AssertReturn(autoInitSpan.isOk(), E_FAIL);
769
770 static const VBOXEXTPACKHLP s_HlpTmpl =
771 {
772 /* u32Version = */ VBOXEXTPACKHLP_VERSION,
773 /* uVBoxFullVersion = */ VBOX_FULL_VERSION,
774 /* uVBoxVersionRevision = */ 0,
775 /* u32Padding = */ 0,
776 /* pszVBoxVersion = */ "",
777 /* pfnFindModule = */ ExtPack::i_hlpFindModule,
778 /* pfnGetFilePath = */ ExtPack::i_hlpGetFilePath,
779 /* pfnGetContext = */ ExtPack::i_hlpGetContext,
780 /* pfnLoadHGCMService = */ ExtPack::i_hlpLoadHGCMService,
781 /* pfnLoadVDPlugin = */ ExtPack::i_hlpLoadVDPlugin,
782 /* pfnUnloadVDPlugin = */ ExtPack::i_hlpUnloadVDPlugin,
783 /* pfnCreateProgress = */ ExtPack::i_hlpCreateProgress,
784 /* pfnGetCanceledProgress = */ ExtPack::i_hlpGetCanceledProgress,
785 /* pfnUpdateProgress = */ ExtPack::i_hlpUpdateProgress,
786 /* pfnNextOperationProgress = */ ExtPack::i_hlpNextOperationProgress,
787 /* pfnWaitOtherProgress = */ ExtPack::i_hlpWaitOtherProgress,
788 /* pfnCompleteProgress = */ ExtPack::i_hlpCompleteProgress,
789 /* pfnCreateEvent = */ ExtPack::i_hlpCreateEvent,
790 /* pfnCreateVetoEvent = */ ExtPack::i_hlpCreateVetoEvent,
791 /* pfnTranslate = */ ExtPack::i_hlpTranslate,
792 /* pfnReserved1 = */ ExtPack::i_hlpReservedN,
793 /* pfnReserved2 = */ ExtPack::i_hlpReservedN,
794 /* pfnReserved3 = */ ExtPack::i_hlpReservedN,
795 /* pfnReserved4 = */ ExtPack::i_hlpReservedN,
796 /* pfnReserved5 = */ ExtPack::i_hlpReservedN,
797 /* pfnReserved6 = */ ExtPack::i_hlpReservedN,
798 /* uReserved7 = */ 0,
799 /* u32EndMarker = */ VBOXEXTPACKHLP_VERSION
800 };
801
802 /*
803 * Allocate + initialize our private data.
804 */
805 m = new Data;
806 VBoxExtPackInitDesc(&m->Desc);
807 m->Desc.strName = a_pszName;
808 RT_ZERO(m->ObjInfoDesc);
809 m->fUsable = false;
810 m->strWhyUnusable = tr("ExtPack::init failed");
811 m->strExtPackPath = a_pszDir;
812 RT_ZERO(m->ObjInfoExtPack);
813 m->strMainModPath.setNull();
814 RT_ZERO(m->ObjInfoMainMod);
815 m->hMainMod = NIL_RTLDRMOD;
816 m->Hlp = s_HlpTmpl;
817 m->Hlp.pszVBoxVersion = RTBldCfgVersion();
818 m->Hlp.uVBoxInternalRevision = RTBldCfgRevision();
819 m->pThis = this;
820 m->pReg = NULL;
821 m->enmContext = a_enmContext;
822 m->fMadeReadyCall = false;
823#ifndef VBOX_COM_INPROC
824 m->pVirtualBox = a_pVirtualBox;
825#else
826 RT_NOREF(a_pVirtualBox);
827#endif
828#ifdef VBOX_WITH_MAIN_NLS
829 m->pTrComponent = NULL;
830#endif
831 /*
832 * Make sure the SUPR3Hardened API works (ignoring errors for now).
833 */
834 int vrc = SUPR3HardenedVerifyInit();
835 if (RT_FAILURE(vrc))
836 LogRel(("SUPR3HardenedVerifyInit failed: %Rrc\n", vrc));
837
838 /*
839 * Probe the extension pack (this code is shared with refresh()).
840 */
841 i_probeAndLoad();
842
843#ifdef VBOX_WITH_MAIN_NLS
844 /* register language files if exist */
845 if (m->pReg != NULL && m->pReg->pszNlsBaseName != NULL)
846 {
847 char szPath[RTPATH_MAX];
848 vrc = RTPathJoin(szPath, sizeof(szPath), a_pszDir, "nls");
849 if (RT_SUCCESS(vrc))
850 {
851 vrc = RTPathAppend(szPath, sizeof(szPath), m->pReg->pszNlsBaseName);
852 if (RT_SUCCESS(vrc))
853 {
854 vrc = VirtualBoxTranslator::registerTranslation(szPath, false, &m->pTrComponent);
855 if (RT_FAILURE(vrc))
856 m->pTrComponent = NULL;
857 }
858 }
859 }
860#endif
861
862 autoInitSpan.setSucceeded();
863 return S_OK;
864}
865
866/**
867 * COM cruft.
868 */
869void ExtPack::FinalRelease()
870{
871 uninit();
872 BaseFinalRelease();
873}
874
875/**
876 * Do the actual cleanup.
877 */
878void ExtPack::uninit()
879{
880 /* Enclose the state transition Ready->InUninit->NotReady */
881 AutoUninitSpan autoUninitSpan(this);
882 if (!autoUninitSpan.uninitDone() && m != NULL)
883 {
884 if (m->hMainMod != NIL_RTLDRMOD)
885 {
886 AssertPtr(m->pReg);
887 if (m->pReg->pfnUnload != NULL)
888 m->pReg->pfnUnload(m->pReg);
889
890 RTLdrClose(m->hMainMod);
891 m->hMainMod = NIL_RTLDRMOD;
892 m->pReg = NULL;
893 }
894
895 VBoxExtPackFreeDesc(&m->Desc);
896
897#ifdef VBOX_WITH_MAIN_NLS
898 if (m->pTrComponent != NULL)
899 VirtualBoxTranslator::unregisterTranslation(m->pTrComponent);
900#endif
901 delete m;
902 m = NULL;
903 }
904}
905
906
907#ifndef VBOX_COM_INPROC
908/**
909 * Calls the installed hook.
910 *
911 * @returns true if we left the lock, false if we didn't.
912 * @param a_pVirtualBox The VirtualBox interface.
913 * @param a_pLock The write lock held by the caller.
914 * @param pErrInfo Where to return error information.
915 */
916bool ExtPack::i_callInstalledHook(IVirtualBox *a_pVirtualBox, AutoWriteLock *a_pLock, PRTERRINFO pErrInfo)
917{
918 if ( m != NULL
919 && m->hMainMod != NIL_RTLDRMOD)
920 {
921 if (m->pReg->pfnInstalled)
922 {
923 ComPtr<ExtPack> ptrSelfRef = this;
924 a_pLock->release();
925 pErrInfo->rc = m->pReg->pfnInstalled(m->pReg, a_pVirtualBox, pErrInfo);
926 a_pLock->acquire();
927 return true;
928 }
929 }
930 pErrInfo->rc = VINF_SUCCESS;
931 return false;
932}
933
934/**
935 * Calls the uninstall hook and closes the module.
936 *
937 * @returns S_OK or COM error status with error information.
938 * @param a_pVirtualBox The VirtualBox interface.
939 * @param a_fForcedRemoval When set, we'll ignore complaints from the
940 * uninstall hook.
941 * @remarks The caller holds the manager's write lock, not released.
942 */
943HRESULT ExtPack::i_callUninstallHookAndClose(IVirtualBox *a_pVirtualBox, bool a_fForcedRemoval)
944{
945 HRESULT hrc = S_OK;
946
947 if ( m != NULL
948 && m->hMainMod != NIL_RTLDRMOD)
949 {
950 if (m->pReg->pfnUninstall)
951 {
952 int vrc = m->pReg->pfnUninstall(m->pReg, a_pVirtualBox);
953 if (RT_FAILURE(vrc))
954 {
955 LogRel(("ExtPack pfnUninstall returned %Rrc for %s\n", vrc, m->Desc.strName.c_str()));
956 if (!a_fForcedRemoval)
957 hrc = setErrorBoth(E_FAIL, vrc, tr("pfnUninstall returned %Rrc"), vrc);
958 }
959 }
960 if (SUCCEEDED(hrc))
961 {
962 RTLdrClose(m->hMainMod);
963 m->hMainMod = NIL_RTLDRMOD;
964 m->pReg = NULL;
965 }
966 }
967
968 return hrc;
969}
970
971/**
972 * Calls the pfnVirtualBoxReady hook.
973 *
974 * @returns true if we left the lock, false if we didn't.
975 * @param a_pVirtualBox The VirtualBox interface.
976 * @param a_pLock The write lock held by the caller.
977 */
978bool ExtPack::i_callVirtualBoxReadyHook(IVirtualBox *a_pVirtualBox, AutoWriteLock *a_pLock)
979{
980 if ( m != NULL
981 && m->fUsable
982 && m->hMainMod != NIL_RTLDRMOD
983 && !m->fMadeReadyCall)
984 {
985 m->fMadeReadyCall = true;
986 if (m->pReg->pfnVirtualBoxReady)
987 {
988 ComPtr<ExtPack> ptrSelfRef = this;
989 a_pLock->release();
990 m->pReg->pfnVirtualBoxReady(m->pReg, a_pVirtualBox);
991 i_notifyCloudProviderManager();
992 a_pLock->acquire();
993 return true;
994 }
995 }
996 return false;
997}
998#endif /* !VBOX_COM_INPROC */
999
1000#ifdef VBOX_COM_INPROC
1001/**
1002 * Calls the pfnConsoleReady hook.
1003 *
1004 * @returns true if we left the lock, false if we didn't.
1005 * @param a_pConsole The Console interface.
1006 * @param a_pLock The write lock held by the caller.
1007 */
1008bool ExtPack::i_callConsoleReadyHook(IConsole *a_pConsole, AutoWriteLock *a_pLock)
1009{
1010 if ( m != NULL
1011 && m->fUsable
1012 && m->hMainMod != NIL_RTLDRMOD
1013 && !m->fMadeReadyCall)
1014 {
1015 m->fMadeReadyCall = true;
1016 if (m->pReg->pfnConsoleReady)
1017 {
1018 ComPtr<ExtPack> ptrSelfRef = this;
1019 a_pLock->release();
1020 m->pReg->pfnConsoleReady(m->pReg, a_pConsole);
1021 a_pLock->acquire();
1022 return true;
1023 }
1024 }
1025 return false;
1026}
1027#endif /* VBOX_COM_INPROC */
1028
1029#ifndef VBOX_COM_INPROC
1030/**
1031 * Calls the pfnVMCreate hook.
1032 *
1033 * @returns true if we left the lock, false if we didn't.
1034 * @param a_pVirtualBox The VirtualBox interface.
1035 * @param a_pMachine The machine interface of the new VM.
1036 * @param a_pLock The write lock held by the caller.
1037 */
1038bool ExtPack::i_callVmCreatedHook(IVirtualBox *a_pVirtualBox, IMachine *a_pMachine, AutoWriteLock *a_pLock)
1039{
1040 if ( m != NULL
1041 && m->hMainMod != NIL_RTLDRMOD
1042 && m->fUsable)
1043 {
1044 if (m->pReg->pfnVMCreated)
1045 {
1046 ComPtr<ExtPack> ptrSelfRef = this;
1047 a_pLock->release();
1048 m->pReg->pfnVMCreated(m->pReg, a_pVirtualBox, a_pMachine);
1049 a_pLock->acquire();
1050 return true;
1051 }
1052 }
1053 return false;
1054}
1055#endif /* !VBOX_COM_INPROC */
1056
1057#ifdef VBOX_COM_INPROC
1058
1059/**
1060 * Calls the pfnVMConfigureVMM hook.
1061 *
1062 * @returns true if we left the lock, false if we didn't.
1063 * @param a_pConsole The console interface.
1064 * @param a_pVM The VM handle.
1065 * @param a_pVMM The VMM function table.
1066 * @param a_pLock The write lock held by the caller.
1067 * @param a_pvrc Where to return the status code of the callback. This
1068 * is always set. LogRel is called on if a failure status
1069 * is returned.
1070 */
1071bool ExtPack::i_callVmConfigureVmmHook(IConsole *a_pConsole, PVM a_pVM, PCVMMR3VTABLE a_pVMM, AutoWriteLock *a_pLock, int *a_pvrc)
1072{
1073 *a_pvrc = VINF_SUCCESS;
1074 if ( m != NULL
1075 && m->hMainMod != NIL_RTLDRMOD
1076 && m->fUsable)
1077 {
1078 if (m->pReg->pfnVMConfigureVMM)
1079 {
1080 ComPtr<ExtPack> ptrSelfRef = this;
1081 a_pLock->release();
1082 int vrc = m->pReg->pfnVMConfigureVMM(m->pReg, a_pConsole, a_pVM, a_pVMM);
1083 *a_pvrc = vrc;
1084 a_pLock->acquire();
1085 if (RT_FAILURE(vrc))
1086 LogRel(("ExtPack pfnVMConfigureVMM returned %Rrc for %s\n", vrc, m->Desc.strName.c_str()));
1087 return true;
1088 }
1089 }
1090 return false;
1091}
1092
1093/**
1094 * Calls the pfnVMPowerOn hook.
1095 *
1096 * @returns true if we left the lock, false if we didn't.
1097 * @param a_pConsole The console interface.
1098 * @param a_pVM The VM handle.
1099 * @param a_pVMM The VMM function table.
1100 * @param a_pLock The write lock held by the caller.
1101 * @param a_pvrc Where to return the status code of the callback. This
1102 * is always set. LogRel is called on if a failure status
1103 * is returned.
1104 */
1105bool ExtPack::i_callVmPowerOnHook(IConsole *a_pConsole, PVM a_pVM, PCVMMR3VTABLE a_pVMM, AutoWriteLock *a_pLock, int *a_pvrc)
1106{
1107 *a_pvrc = VINF_SUCCESS;
1108 if ( m != NULL
1109 && m->hMainMod != NIL_RTLDRMOD
1110 && m->fUsable)
1111 {
1112 if (m->pReg->pfnVMPowerOn)
1113 {
1114 ComPtr<ExtPack> ptrSelfRef = this;
1115 a_pLock->release();
1116 int vrc = m->pReg->pfnVMPowerOn(m->pReg, a_pConsole, a_pVM, a_pVMM);
1117 *a_pvrc = vrc;
1118 a_pLock->acquire();
1119 if (RT_FAILURE(vrc))
1120 LogRel(("ExtPack pfnVMPowerOn returned %Rrc for %s\n", vrc, m->Desc.strName.c_str()));
1121 return true;
1122 }
1123 }
1124 return false;
1125}
1126
1127/**
1128 * Calls the pfnVMPowerOff hook.
1129 *
1130 * @returns true if we left the lock, false if we didn't.
1131 * @param a_pConsole The console interface.
1132 * @param a_pVM The VM handle.
1133 * @param a_pVMM The VMM function table.
1134 * @param a_pLock The write lock held by the caller.
1135 */
1136bool ExtPack::i_callVmPowerOffHook(IConsole *a_pConsole, PVM a_pVM, PCVMMR3VTABLE a_pVMM, AutoWriteLock *a_pLock)
1137{
1138 if ( m != NULL
1139 && m->hMainMod != NIL_RTLDRMOD
1140 && m->fUsable)
1141 {
1142 if (m->pReg->pfnVMPowerOff)
1143 {
1144 ComPtr<ExtPack> ptrSelfRef = this;
1145 a_pLock->release();
1146 m->pReg->pfnVMPowerOff(m->pReg, a_pConsole, a_pVM, a_pVMM);
1147 a_pLock->acquire();
1148 return true;
1149 }
1150 }
1151 return false;
1152}
1153
1154#endif /* VBOX_COM_INPROC */
1155
1156/**
1157 * Check if the extension pack is usable and has an VRDE module.
1158 *
1159 * @returns S_OK or COM error status with error information.
1160 *
1161 * @remarks Caller holds the extension manager lock for reading, no locking
1162 * necessary.
1163 */
1164HRESULT ExtPack::i_checkVrde(void)
1165{
1166 HRESULT hrc;
1167 if ( m != NULL
1168 && m->fUsable)
1169 {
1170 if (m->Desc.strVrdeModule.isNotEmpty())
1171 hrc = S_OK;
1172 else
1173 hrc = setError(E_FAIL, tr("The extension pack '%s' does not include a VRDE module"), m->Desc.strName.c_str());
1174 }
1175 else
1176 hrc = setError(E_FAIL, "%s", m->strWhyUnusable.c_str());
1177 return hrc;
1178}
1179
1180/**
1181 * Check if the extension pack is usable and has a cryptographic module.
1182 *
1183 * @returns S_OK or COM error status with error information.
1184 *
1185 * @remarks Caller holds the extension manager lock for reading, no locking
1186 * necessary.
1187 */
1188HRESULT ExtPack::i_checkCrypto(void)
1189{
1190 HRESULT hrc;
1191 if ( m != NULL
1192 && m->fUsable)
1193 {
1194 if (m->Desc.strCryptoModule.isNotEmpty())
1195 hrc = S_OK;
1196 else
1197 hrc = setError(E_FAIL, tr("The extension pack '%s' does not include a cryptographic module"), m->Desc.strName.c_str());
1198 }
1199 else
1200 hrc = setError(E_FAIL, "%s", m->strWhyUnusable.c_str());
1201 return hrc;
1202}
1203
1204/**
1205 * Same as checkVrde(), except that it also resolves the path to the module.
1206 *
1207 * @returns S_OK or COM error status with error information.
1208 * @param a_pstrVrdeLibrary Where to return the path on success.
1209 *
1210 * @remarks Caller holds the extension manager lock for reading, no locking
1211 * necessary.
1212 */
1213HRESULT ExtPack::i_getVrdpLibraryName(Utf8Str *a_pstrVrdeLibrary)
1214{
1215 HRESULT hrc = i_checkVrde();
1216 if (SUCCEEDED(hrc))
1217 {
1218 if (i_findModule(m->Desc.strVrdeModule.c_str(), NULL, VBOXEXTPACKMODKIND_R3,
1219 a_pstrVrdeLibrary, NULL /*a_pfNative*/, NULL /*a_pObjInfo*/))
1220 hrc = S_OK;
1221 else
1222 hrc = setError(E_FAIL, tr("Failed to locate the VRDE module '%s' in extension pack '%s'"),
1223 m->Desc.strVrdeModule.c_str(), m->Desc.strName.c_str());
1224 }
1225 return hrc;
1226}
1227
1228/**
1229 * Same as i_checkCrypto(), except that it also resolves the path to the module.
1230 *
1231 * @returns S_OK or COM error status with error information.
1232 * @param a_pstrCryptoLibrary Where to return the path on success.
1233 *
1234 * @remarks Caller holds the extension manager lock for reading, no locking
1235 * necessary.
1236 */
1237HRESULT ExtPack::i_getCryptoLibraryName(Utf8Str *a_pstrCryptoLibrary)
1238{
1239 HRESULT hrc = i_checkCrypto();
1240 if (SUCCEEDED(hrc))
1241 {
1242 if (i_findModule(m->Desc.strCryptoModule.c_str(), NULL, VBOXEXTPACKMODKIND_R3,
1243 a_pstrCryptoLibrary, NULL /*a_pfNative*/, NULL /*a_pObjInfo*/))
1244 hrc = S_OK;
1245 else
1246 hrc = setError(E_FAIL, tr("Failed to locate the cryptographic module '%s' in extension pack '%s'"),
1247 m->Desc.strCryptoModule.c_str(), m->Desc.strName.c_str());
1248 }
1249 return hrc;
1250}
1251
1252/**
1253 * Resolves the path to the module.
1254 *
1255 * @returns S_OK or COM error status with error information.
1256 * @param a_pszModuleName The library.
1257 * @param a_pstrLibrary Where to return the path on success.
1258 *
1259 * @remarks Caller holds the extension manager lock for reading, no locking
1260 * necessary.
1261 */
1262HRESULT ExtPack::i_getLibraryName(const char *a_pszModuleName, Utf8Str *a_pstrLibrary)
1263{
1264 HRESULT hrc;
1265 if (i_findModule(a_pszModuleName, NULL, VBOXEXTPACKMODKIND_R3,
1266 a_pstrLibrary, NULL /*a_pfNative*/, NULL /*a_pObjInfo*/))
1267 hrc = S_OK;
1268 else
1269 hrc = setError(E_FAIL, tr("Failed to locate the module '%s' in extension pack '%s'"),
1270 a_pszModuleName, m->Desc.strName.c_str());
1271 return hrc;
1272}
1273
1274/**
1275 * Check if this extension pack wishes to be the default VRDE provider.
1276 *
1277 * @returns @c true if it wants to and it is in a usable state, otherwise
1278 * @c false.
1279 *
1280 * @remarks Caller holds the extension manager lock for reading, no locking
1281 * necessary.
1282 */
1283bool ExtPack::i_wantsToBeDefaultVrde(void) const
1284{
1285 return m->fUsable
1286 && m->Desc.strVrdeModule.isNotEmpty();
1287}
1288
1289/**
1290 * Check if this extension pack wishes to be the default cryptographic provider.
1291 *
1292 * @returns @c true if it wants to and it is in a usable state, otherwise
1293 * @c false.
1294 *
1295 * @remarks Caller holds the extension manager lock for reading, no locking
1296 * necessary.
1297 */
1298bool ExtPack::i_wantsToBeDefaultCrypto(void) const
1299{
1300 return m->fUsable
1301 && m->Desc.strCryptoModule.isNotEmpty();
1302}
1303
1304/**
1305 * Refreshes the extension pack state.
1306 *
1307 * This is called by the manager so that the on disk changes are picked up.
1308 *
1309 * @returns S_OK or COM error status with error information.
1310 *
1311 * @param a_pfCanDelete Optional can-delete-this-object output indicator.
1312 *
1313 * @remarks Caller holds the extension manager lock for writing.
1314 * @remarks Only called in VBoxSVC.
1315 */
1316HRESULT ExtPack::i_refresh(bool *a_pfCanDelete)
1317{
1318 if (a_pfCanDelete)
1319 *a_pfCanDelete = false;
1320
1321 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS); /* for the COMGETTERs */
1322
1323 /*
1324 * Has the module been deleted?
1325 */
1326 RTFSOBJINFO ObjInfoExtPack;
1327 int vrc = RTPathQueryInfoEx(m->strExtPackPath.c_str(), &ObjInfoExtPack, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
1328 if ( RT_FAILURE(vrc)
1329 || !RTFS_IS_DIRECTORY(ObjInfoExtPack.Attr.fMode))
1330 {
1331 if (a_pfCanDelete)
1332 *a_pfCanDelete = true;
1333 return S_OK;
1334 }
1335
1336 /*
1337 * We've got a directory, so try query file system object info for the
1338 * files we are interested in as well.
1339 */
1340 RTFSOBJINFO ObjInfoDesc;
1341 char szDescFilePath[RTPATH_MAX];
1342 vrc = RTPathJoin(szDescFilePath, sizeof(szDescFilePath), m->strExtPackPath.c_str(), VBOX_EXTPACK_DESCRIPTION_NAME);
1343 if (RT_SUCCESS(vrc))
1344 vrc = RTPathQueryInfoEx(szDescFilePath, &ObjInfoDesc, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
1345 if (RT_FAILURE(vrc))
1346 RT_ZERO(ObjInfoDesc);
1347
1348 RTFSOBJINFO ObjInfoMainMod;
1349 if (m->strMainModPath.isNotEmpty())
1350 vrc = RTPathQueryInfoEx(m->strMainModPath.c_str(), &ObjInfoMainMod, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
1351 if (m->strMainModPath.isEmpty() || RT_FAILURE(vrc))
1352 RT_ZERO(ObjInfoMainMod);
1353
1354 /*
1355 * If we have a usable module already, just verify that things haven't
1356 * changed since we loaded it.
1357 */
1358 if (m->fUsable)
1359 {
1360 if (m->hMainMod == NIL_RTLDRMOD)
1361 i_probeAndLoad();
1362 else if ( !i_objinfoIsEqual(&ObjInfoDesc, &m->ObjInfoDesc)
1363 || !i_objinfoIsEqual(&ObjInfoMainMod, &m->ObjInfoMainMod)
1364 || !i_objinfoIsEqual(&ObjInfoExtPack, &m->ObjInfoExtPack) )
1365 {
1366 /** @todo not important, so it can wait. */
1367 }
1368 }
1369 /*
1370 * Ok, it is currently not usable. If anything has changed since last time
1371 * reprobe the extension pack.
1372 */
1373 else if ( !i_objinfoIsEqual(&ObjInfoDesc, &m->ObjInfoDesc)
1374 || !i_objinfoIsEqual(&ObjInfoMainMod, &m->ObjInfoMainMod)
1375 || !i_objinfoIsEqual(&ObjInfoExtPack, &m->ObjInfoExtPack) )
1376 i_probeAndLoad();
1377
1378 return S_OK;
1379}
1380
1381#ifndef VBOX_COM_INPROC
1382/**
1383 * Checks if there are cloud providers vetoing extension pack uninstall.
1384 *
1385 * This needs going through the cloud provider singleton in VirtualBox,
1386 * the job cannot be done purely by using the code in the extension pack).
1387 * It cannot be integrated into i_callUninstallHookAndClose, because it
1388 * can only do its job when the extpack lock is not held, whereas the
1389 * actual uninstall must be done with the lock held all the time for
1390 * consistency reasons.
1391 *
1392 * This is called when uninstalling or replacing an extension pack.
1393 *
1394 * @returns true / false
1395 */
1396bool ExtPack::i_areThereCloudProviderUninstallVetos()
1397{
1398 Assert(m->pVirtualBox != NULL); /* Only called from VBoxSVC. */
1399
1400 ComObjPtr<CloudProviderManager> cpm(m->pVirtualBox->i_getCloudProviderManager());
1401 AssertReturn(!cpm.isNull(), false);
1402
1403 return !cpm->i_canRemoveExtPack(static_cast<IExtPack *>(this));
1404}
1405
1406/**
1407 * Notifies the Cloud Provider Manager that there is a new extension pack.
1408 *
1409 * This is called when installing an extension pack.
1410 */
1411void ExtPack::i_notifyCloudProviderManager()
1412{
1413 Assert(m->pVirtualBox != NULL); /* Only called from VBoxSVC. */
1414
1415 ComObjPtr<CloudProviderManager> cpm(m->pVirtualBox->i_getCloudProviderManager());
1416 AssertReturnVoid(!cpm.isNull());
1417
1418 cpm->i_addExtPack(static_cast<IExtPack *>(this));
1419}
1420
1421#endif /* !VBOX_COM_INPROC */
1422
1423/**
1424 * Probes the extension pack, loading the main dll and calling its registration
1425 * entry point.
1426 *
1427 * This updates the state accordingly, the strWhyUnusable and fUnusable members
1428 * being the most important ones.
1429 */
1430void ExtPack::i_probeAndLoad(void)
1431{
1432 m->fUsable = false;
1433 m->fMadeReadyCall = false;
1434
1435 /*
1436 * Query the file system info for the extension pack directory. This and
1437 * all other file system info we save is for the benefit of refresh().
1438 */
1439 int vrc = RTPathQueryInfoEx(m->strExtPackPath.c_str(), &m->ObjInfoExtPack, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
1440 if (RT_FAILURE(vrc))
1441 {
1442 m->strWhyUnusable.printf(tr("RTPathQueryInfoEx on '%s' failed: %Rrc"), m->strExtPackPath.c_str(), vrc);
1443 return;
1444 }
1445 if (!RTFS_IS_DIRECTORY(m->ObjInfoExtPack.Attr.fMode))
1446 {
1447 if (RTFS_IS_SYMLINK(m->ObjInfoExtPack.Attr.fMode))
1448 m->strWhyUnusable.printf(tr("'%s' is a symbolic link, this is not allowed"),
1449 m->strExtPackPath.c_str(), vrc);
1450 else if (RTFS_IS_FILE(m->ObjInfoExtPack.Attr.fMode))
1451 m->strWhyUnusable.printf(tr("'%s' is a symbolic file, not a directory"),
1452 m->strExtPackPath.c_str(), vrc);
1453 else
1454 m->strWhyUnusable.printf(tr("'%s' is not a directory (fMode=%#x)"),
1455 m->strExtPackPath.c_str(), m->ObjInfoExtPack.Attr.fMode);
1456 return;
1457 }
1458
1459 RTERRINFOSTATIC ErrInfo;
1460 RTErrInfoInitStatic(&ErrInfo);
1461 vrc = SUPR3HardenedVerifyDir(m->strExtPackPath.c_str(), true /*fRecursive*/, true /*fCheckFiles*/, &ErrInfo.Core);
1462 if (RT_FAILURE(vrc))
1463 {
1464 m->strWhyUnusable.printf("%s (rc=%Rrc)", ErrInfo.Core.pszMsg, vrc);
1465 return;
1466 }
1467
1468 /*
1469 * Read the description file.
1470 */
1471 RTCString strSavedName(m->Desc.strName);
1472 RTCString *pStrLoadErr = VBoxExtPackLoadDesc(m->strExtPackPath.c_str(), &m->Desc, &m->ObjInfoDesc);
1473 if (pStrLoadErr != NULL)
1474 {
1475 m->strWhyUnusable.printf(tr("Failed to load '%s/%s': %s"),
1476 m->strExtPackPath.c_str(), VBOX_EXTPACK_DESCRIPTION_NAME, pStrLoadErr->c_str());
1477 m->Desc.strName = strSavedName;
1478 delete pStrLoadErr;
1479 return;
1480 }
1481
1482 /*
1483 * Make sure the XML name and directory matches.
1484 */
1485 if (!m->Desc.strName.equalsIgnoreCase(strSavedName))
1486 {
1487 m->strWhyUnusable.printf(tr("The description name ('%s') and directory name ('%s') does not match"),
1488 m->Desc.strName.c_str(), strSavedName.c_str());
1489 m->Desc.strName = strSavedName;
1490 return;
1491 }
1492
1493 /*
1494 * Load the main DLL and call the predefined entry point.
1495 */
1496#ifndef VBOX_COM_INPROC
1497 const char *pszMainModule = m->Desc.strMainModule.c_str();
1498#else
1499 const char *pszMainModule = m->Desc.strMainVMModule.c_str();
1500 if (m->Desc.strMainVMModule.isEmpty())
1501 {
1502 /*
1503 * We're good! The main module for VM processes is optional.
1504 */
1505 m->fUsable = true;
1506 m->strWhyUnusable.setNull();
1507 return;
1508 }
1509#endif
1510 bool fIsNative;
1511 if (!i_findModule(pszMainModule, NULL /* default extension */, VBOXEXTPACKMODKIND_R3,
1512 &m->strMainModPath, &fIsNative, &m->ObjInfoMainMod))
1513 {
1514 m->strWhyUnusable.printf(tr("Failed to locate the main module ('%s')"), pszMainModule);
1515 return;
1516 }
1517
1518 vrc = SUPR3HardenedVerifyPlugIn(m->strMainModPath.c_str(), &ErrInfo.Core);
1519 if (RT_FAILURE(vrc))
1520 {
1521 m->strWhyUnusable.printf("%s", ErrInfo.Core.pszMsg);
1522 return;
1523 }
1524
1525 if (fIsNative)
1526 {
1527 vrc = SUPR3HardenedLdrLoadPlugIn(m->strMainModPath.c_str(), &m->hMainMod, &ErrInfo.Core);
1528 if (RT_FAILURE(vrc))
1529 {
1530 m->hMainMod = NIL_RTLDRMOD;
1531 m->strWhyUnusable.printf(tr("Failed to load the main module ('%s'): %Rrc - %s"),
1532 m->strMainModPath.c_str(), vrc, ErrInfo.Core.pszMsg);
1533 return;
1534 }
1535 }
1536 else
1537 {
1538 m->strWhyUnusable.printf(tr("Only native main modules are currently supported"));
1539 return;
1540 }
1541
1542 /*
1543 * Resolve the predefined entry point.
1544 */
1545#ifndef VBOX_COM_INPROC
1546 const char *pszMainEntryPoint = VBOX_EXTPACK_MAIN_MOD_ENTRY_POINT;
1547 PFNVBOXEXTPACKREGISTER pfnRegistration;
1548 uint32_t uVersion = VBOXEXTPACKREG_VERSION;
1549#else
1550 const char *pszMainEntryPoint = VBOX_EXTPACK_MAIN_VM_MOD_ENTRY_POINT;
1551 PFNVBOXEXTPACKVMREGISTER pfnRegistration;
1552 uint32_t uVersion = VBOXEXTPACKVMREG_VERSION;
1553#endif
1554 vrc = RTLdrGetSymbol(m->hMainMod, pszMainEntryPoint, (void **)&pfnRegistration);
1555 if (RT_SUCCESS(vrc))
1556 {
1557 RTErrInfoClear(&ErrInfo.Core);
1558 vrc = pfnRegistration(&m->Hlp, &m->pReg, &ErrInfo.Core);
1559 if ( RT_SUCCESS(vrc)
1560 && !RTErrInfoIsSet(&ErrInfo.Core)
1561 && RT_VALID_PTR(m->pReg))
1562 {
1563 if ( VBOXEXTPACK_IS_MAJOR_VER_EQUAL(m->pReg->u32Version, uVersion)
1564 && m->pReg->u32EndMarker == m->pReg->u32Version)
1565 {
1566#ifndef VBOX_COM_INPROC
1567 if ( (!m->pReg->pfnInstalled || RT_VALID_PTR(m->pReg->pfnInstalled))
1568 && (!m->pReg->pfnUninstall || RT_VALID_PTR(m->pReg->pfnUninstall))
1569 && (!m->pReg->pfnVirtualBoxReady || RT_VALID_PTR(m->pReg->pfnVirtualBoxReady))
1570 && (!m->pReg->pfnUnload || RT_VALID_PTR(m->pReg->pfnUnload))
1571 && (!m->pReg->pfnVMCreated || RT_VALID_PTR(m->pReg->pfnVMCreated))
1572 && (!m->pReg->pfnQueryObject || RT_VALID_PTR(m->pReg->pfnQueryObject))
1573 )
1574 {
1575 /*
1576 * We're good!
1577 */
1578 m->fUsable = true;
1579 m->strWhyUnusable.setNull();
1580 return;
1581 }
1582#else
1583 if ( (!m->pReg->pfnConsoleReady || RT_VALID_PTR(m->pReg->pfnConsoleReady))
1584 && (!m->pReg->pfnUnload || RT_VALID_PTR(m->pReg->pfnUnload))
1585 && (!m->pReg->pfnVMConfigureVMM || RT_VALID_PTR(m->pReg->pfnVMConfigureVMM))
1586 && (!m->pReg->pfnVMPowerOn || RT_VALID_PTR(m->pReg->pfnVMPowerOn))
1587 && (!m->pReg->pfnVMPowerOff || RT_VALID_PTR(m->pReg->pfnVMPowerOff))
1588 && (!m->pReg->pfnQueryObject || RT_VALID_PTR(m->pReg->pfnQueryObject))
1589 )
1590 {
1591 /*
1592 * We're good!
1593 */
1594 m->fUsable = true;
1595 m->strWhyUnusable.setNull();
1596 return;
1597 }
1598#endif
1599
1600 m->strWhyUnusable = tr("The registration structure contains one or more invalid function pointers");
1601 }
1602 else
1603 m->strWhyUnusable.printf(tr("Unsupported registration structure version %u.%u"),
1604 RT_HIWORD(m->pReg->u32Version), RT_LOWORD(m->pReg->u32Version));
1605 }
1606 else
1607 m->strWhyUnusable.printf(tr("%s returned %Rrc, pReg=%p ErrInfo='%s'"),
1608 pszMainEntryPoint, vrc, m->pReg, ErrInfo.Core.pszMsg);
1609 m->pReg = NULL;
1610 }
1611 else
1612 m->strWhyUnusable.printf(tr("Failed to resolve exported symbol '%s' in the main module: %Rrc"),
1613 pszMainEntryPoint, vrc);
1614
1615 RTLdrClose(m->hMainMod);
1616 m->hMainMod = NIL_RTLDRMOD;
1617}
1618
1619/**
1620 * Finds a module.
1621 *
1622 * @returns true if found, false if not.
1623 * @param a_pszName The module base name (no extension).
1624 * @param a_pszExt The extension. If NULL we use default
1625 * extensions.
1626 * @param a_enmKind The kind of module to locate.
1627 * @param a_pStrFound Where to return the path to the module we've
1628 * found.
1629 * @param a_pfNative Where to return whether this is a native module
1630 * or an agnostic one. Optional.
1631 * @param a_pObjInfo Where to return the file system object info for
1632 * the module. Optional.
1633 */
1634bool ExtPack::i_findModule(const char *a_pszName, const char *a_pszExt, VBOXEXTPACKMODKIND a_enmKind,
1635 Utf8Str *a_pStrFound, bool *a_pfNative, PRTFSOBJINFO a_pObjInfo) const
1636{
1637 /*
1638 * Try the native path first.
1639 */
1640 char szPath[RTPATH_MAX];
1641 int vrc = RTPathJoin(szPath, sizeof(szPath), m->strExtPackPath.c_str(), RTBldCfgTargetDotArch());
1642 AssertLogRelRCReturn(vrc, false);
1643 vrc = RTPathAppend(szPath, sizeof(szPath), a_pszName);
1644 AssertLogRelRCReturn(vrc, false);
1645 if (!a_pszExt)
1646 {
1647 const char *pszDefExt;
1648 switch (a_enmKind)
1649 {
1650 case VBOXEXTPACKMODKIND_RC: pszDefExt = ".rc"; break;
1651 case VBOXEXTPACKMODKIND_R0: pszDefExt = ".r0"; break;
1652 case VBOXEXTPACKMODKIND_R3: pszDefExt = RTLdrGetSuff(); break;
1653 default:
1654 AssertFailedReturn(false);
1655 }
1656 vrc = RTStrCat(szPath, sizeof(szPath), pszDefExt);
1657 AssertLogRelRCReturn(vrc, false);
1658 }
1659
1660 RTFSOBJINFO ObjInfo;
1661 if (!a_pObjInfo)
1662 a_pObjInfo = &ObjInfo;
1663 vrc = RTPathQueryInfo(szPath, a_pObjInfo, RTFSOBJATTRADD_UNIX);
1664 if (RT_SUCCESS(vrc) && RTFS_IS_FILE(a_pObjInfo->Attr.fMode))
1665 {
1666 if (a_pfNative)
1667 *a_pfNative = true;
1668 *a_pStrFound = szPath;
1669 return true;
1670 }
1671
1672 /*
1673 * Try the platform agnostic modules.
1674 */
1675 /* gcc.x86/module.rel */
1676 char szSubDir[32];
1677 RTStrPrintf(szSubDir, sizeof(szSubDir), "%s.%s", RTBldCfgCompiler(), RTBldCfgTargetArch());
1678 vrc = RTPathJoin(szPath, sizeof(szPath), m->strExtPackPath.c_str(), szSubDir);
1679 AssertLogRelRCReturn(vrc, false);
1680 vrc = RTPathAppend(szPath, sizeof(szPath), a_pszName);
1681 AssertLogRelRCReturn(vrc, false);
1682 if (!a_pszExt)
1683 {
1684 vrc = RTStrCat(szPath, sizeof(szPath), ".rel");
1685 AssertLogRelRCReturn(vrc, false);
1686 }
1687 vrc = RTPathQueryInfo(szPath, a_pObjInfo, RTFSOBJATTRADD_UNIX);
1688 if (RT_SUCCESS(vrc) && RTFS_IS_FILE(a_pObjInfo->Attr.fMode))
1689 {
1690 if (a_pfNative)
1691 *a_pfNative = false;
1692 *a_pStrFound = szPath;
1693 return true;
1694 }
1695
1696 /* x86/module.rel */
1697 vrc = RTPathJoin(szPath, sizeof(szPath), m->strExtPackPath.c_str(), RTBldCfgTargetArch());
1698 AssertLogRelRCReturn(vrc, false);
1699 vrc = RTPathAppend(szPath, sizeof(szPath), a_pszName);
1700 AssertLogRelRCReturn(vrc, false);
1701 if (!a_pszExt)
1702 {
1703 vrc = RTStrCat(szPath, sizeof(szPath), ".rel");
1704 AssertLogRelRCReturn(vrc, false);
1705 }
1706 vrc = RTPathQueryInfo(szPath, a_pObjInfo, RTFSOBJATTRADD_UNIX);
1707 if (RT_SUCCESS(vrc) && RTFS_IS_FILE(a_pObjInfo->Attr.fMode))
1708 {
1709 if (a_pfNative)
1710 *a_pfNative = false;
1711 *a_pStrFound = szPath;
1712 return true;
1713 }
1714
1715 return false;
1716}
1717
1718/**
1719 * Compares two file system object info structures.
1720 *
1721 * @returns true if equal, false if not.
1722 * @param pObjInfo1 The first.
1723 * @param pObjInfo2 The second.
1724 * @todo IPRT should do this, really.
1725 */
1726/* static */ bool ExtPack::i_objinfoIsEqual(PCRTFSOBJINFO pObjInfo1, PCRTFSOBJINFO pObjInfo2)
1727{
1728 if (!RTTimeSpecIsEqual(&pObjInfo1->ModificationTime, &pObjInfo2->ModificationTime))
1729 return false;
1730 if (!RTTimeSpecIsEqual(&pObjInfo1->ChangeTime, &pObjInfo2->ChangeTime))
1731 return false;
1732 if (!RTTimeSpecIsEqual(&pObjInfo1->BirthTime, &pObjInfo2->BirthTime))
1733 return false;
1734 if (pObjInfo1->cbObject != pObjInfo2->cbObject)
1735 return false;
1736 if (pObjInfo1->Attr.fMode != pObjInfo2->Attr.fMode)
1737 return false;
1738 if (pObjInfo1->Attr.enmAdditional == pObjInfo2->Attr.enmAdditional)
1739 {
1740 switch (pObjInfo1->Attr.enmAdditional)
1741 {
1742 case RTFSOBJATTRADD_UNIX:
1743 if (pObjInfo1->Attr.u.Unix.uid != pObjInfo2->Attr.u.Unix.uid)
1744 return false;
1745 if (pObjInfo1->Attr.u.Unix.gid != pObjInfo2->Attr.u.Unix.gid)
1746 return false;
1747 if (pObjInfo1->Attr.u.Unix.INodeIdDevice != pObjInfo2->Attr.u.Unix.INodeIdDevice)
1748 return false;
1749 if (pObjInfo1->Attr.u.Unix.INodeId != pObjInfo2->Attr.u.Unix.INodeId)
1750 return false;
1751 if (pObjInfo1->Attr.u.Unix.GenerationId != pObjInfo2->Attr.u.Unix.GenerationId)
1752 return false;
1753 break;
1754 default:
1755 break;
1756 }
1757 }
1758 return true;
1759}
1760
1761
1762/**
1763 * @interface_method_impl{VBOXEXTPACKHLP,pfnFindModule}
1764 */
1765/*static*/ DECLCALLBACK(int)
1766ExtPack::i_hlpFindModule(PCVBOXEXTPACKHLP pHlp, const char *pszName, const char *pszExt, VBOXEXTPACKMODKIND enmKind,
1767 char *pszFound, size_t cbFound, bool *pfNative)
1768{
1769 /*
1770 * Validate the input and get our bearings.
1771 */
1772 AssertPtrReturn(pszName, VERR_INVALID_POINTER);
1773 AssertPtrNullReturn(pszExt, VERR_INVALID_POINTER);
1774 AssertPtrReturn(pszFound, VERR_INVALID_POINTER);
1775 AssertPtrNullReturn(pfNative, VERR_INVALID_POINTER);
1776 AssertReturn(enmKind > VBOXEXTPACKMODKIND_INVALID && enmKind < VBOXEXTPACKMODKIND_END, VERR_INVALID_PARAMETER);
1777
1778 AssertPtrReturn(pHlp, VERR_INVALID_POINTER);
1779 AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, VERR_INVALID_POINTER);
1780 ExtPack::Data *pData = RT_FROM_CPP_MEMBER(pHlp, Data, Hlp);
1781 AssertPtrReturn(pData, VERR_INVALID_POINTER);
1782 ExtPack *pThis = pData->pThis;
1783 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1784
1785 /*
1786 * This is just a wrapper around findModule.
1787 */
1788 Utf8Str strFound;
1789 if (pThis->i_findModule(pszName, pszExt, enmKind, &strFound, pfNative, NULL))
1790 return RTStrCopy(pszFound, cbFound, strFound.c_str());
1791 return VERR_FILE_NOT_FOUND;
1792}
1793
1794/**
1795 * @interface_method_impl{VBOXEXTPACKHLP,pfnGetFilePath}
1796 */
1797/*static*/ DECLCALLBACK(int)
1798ExtPack::i_hlpGetFilePath(PCVBOXEXTPACKHLP pHlp, const char *pszFilename, char *pszPath, size_t cbPath)
1799{
1800 /*
1801 * Validate the input and get our bearings.
1802 */
1803 AssertPtrReturn(pszFilename, VERR_INVALID_POINTER);
1804 AssertPtrReturn(pszPath, VERR_INVALID_POINTER);
1805 AssertReturn(cbPath > 0, VERR_BUFFER_OVERFLOW);
1806
1807 AssertPtrReturn(pHlp, VERR_INVALID_POINTER);
1808 AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, VERR_INVALID_POINTER);
1809 ExtPack::Data *pData = RT_FROM_CPP_MEMBER(pHlp, Data, Hlp);
1810 AssertPtrReturn(pData, VERR_INVALID_POINTER);
1811
1812 /*
1813 * This is a simple RTPathJoin, no checking if things exists or anything.
1814 */
1815 int vrc = RTPathJoin(pszPath, cbPath, pData->strExtPackPath.c_str(), pszFilename);
1816 if (RT_FAILURE(vrc))
1817 RT_BZERO(pszPath, cbPath);
1818 return vrc;
1819}
1820
1821/**
1822 * @interface_method_impl{VBOXEXTPACKHLP,pfnGetContext}
1823 */
1824/*static*/ DECLCALLBACK(VBOXEXTPACKCTX)
1825ExtPack::i_hlpGetContext(PCVBOXEXTPACKHLP pHlp)
1826{
1827 /*
1828 * Validate the input and get our bearings.
1829 */
1830 AssertPtrReturn(pHlp, VBOXEXTPACKCTX_INVALID);
1831 AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, VBOXEXTPACKCTX_INVALID);
1832 ExtPack::Data *pData = RT_FROM_CPP_MEMBER(pHlp, Data, Hlp);
1833 AssertPtrReturn(pData, VBOXEXTPACKCTX_INVALID);
1834
1835 return pData->enmContext;
1836}
1837
1838/**
1839 * @interface_method_impl{VBOXEXTPACKHLP,pfnLoadHGCMService}
1840 */
1841/*static*/ DECLCALLBACK(int)
1842ExtPack::i_hlpLoadHGCMService(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IConsole) *pConsole,
1843 const char *pszServiceLibrary, const char *pszServiceName)
1844{
1845#ifdef VBOX_COM_INPROC
1846 /*
1847 * Validate the input and get our bearings.
1848 */
1849 AssertPtrReturn(pszServiceLibrary, VERR_INVALID_POINTER);
1850 AssertPtrReturn(pszServiceName, VERR_INVALID_POINTER);
1851
1852 AssertPtrReturn(pHlp, VERR_INVALID_POINTER);
1853 AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, VERR_INVALID_POINTER);
1854 ExtPack::Data *pData = RT_FROM_CPP_MEMBER(pHlp, Data, Hlp);
1855 AssertPtrReturn(pData, VERR_INVALID_POINTER);
1856 ExtPack *pThis = pData->pThis;
1857 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1858 AssertPtrReturn(pConsole, VERR_INVALID_POINTER);
1859
1860 Console *pCon = (Console *)pConsole;
1861 return pCon->i_hgcmLoadService(pszServiceLibrary, pszServiceName);
1862#else
1863 RT_NOREF(pHlp, pConsole, pszServiceLibrary, pszServiceName);
1864 return VERR_INVALID_STATE;
1865#endif
1866}
1867
1868/**
1869 * @interface_method_impl{VBOXEXTPACKHLP,pfnLoadVDPlugin}
1870 */
1871/*static*/ DECLCALLBACK(int)
1872ExtPack::i_hlpLoadVDPlugin(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IVirtualBox) *pVirtualBox, const char *pszPluginLibrary)
1873{
1874#ifndef VBOX_COM_INPROC
1875 /*
1876 * Validate the input and get our bearings.
1877 */
1878 AssertPtrReturn(pszPluginLibrary, VERR_INVALID_POINTER);
1879
1880 AssertPtrReturn(pHlp, VERR_INVALID_POINTER);
1881 AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, VERR_INVALID_POINTER);
1882 ExtPack::Data *pData = RT_FROM_CPP_MEMBER(pHlp, Data, Hlp);
1883 AssertPtrReturn(pData, VERR_INVALID_POINTER);
1884 ExtPack *pThis = pData->pThis;
1885 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1886 AssertPtrReturn(pVirtualBox, VERR_INVALID_POINTER);
1887
1888 VirtualBox *pVBox = (VirtualBox *)pVirtualBox;
1889 return pVBox->i_loadVDPlugin(pszPluginLibrary);
1890#else
1891 RT_NOREF(pHlp, pVirtualBox, pszPluginLibrary);
1892 return VERR_INVALID_STATE;
1893#endif
1894}
1895
1896/**
1897 * @interface_method_impl{VBOXEXTPACKHLP,pfnUnloadVDPlugin}
1898 */
1899/*static*/ DECLCALLBACK(int)
1900ExtPack::i_hlpUnloadVDPlugin(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IVirtualBox) *pVirtualBox, const char *pszPluginLibrary)
1901{
1902#ifndef VBOX_COM_INPROC
1903 /*
1904 * Validate the input and get our bearings.
1905 */
1906 AssertPtrReturn(pszPluginLibrary, VERR_INVALID_POINTER);
1907
1908 AssertPtrReturn(pHlp, VERR_INVALID_POINTER);
1909 AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, VERR_INVALID_POINTER);
1910 ExtPack::Data *pData = RT_FROM_CPP_MEMBER(pHlp, Data, Hlp);
1911 AssertPtrReturn(pData, VERR_INVALID_POINTER);
1912 ExtPack *pThis = pData->pThis;
1913 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
1914 AssertPtrReturn(pVirtualBox, VERR_INVALID_POINTER);
1915
1916 VirtualBox *pVBox = (VirtualBox *)pVirtualBox;
1917 return pVBox->i_unloadVDPlugin(pszPluginLibrary);
1918#else
1919 RT_NOREF(pHlp, pVirtualBox, pszPluginLibrary);
1920 return VERR_INVALID_STATE;
1921#endif
1922}
1923
1924/**
1925 * @interface_method_impl{VBOXEXTPACKHLP,pfnCreateProgress}
1926 */
1927/*static*/ DECLCALLBACK(uint32_t)
1928ExtPack::i_hlpCreateProgress(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IUnknown) *pInitiator,
1929 const char *pcszDescription, uint32_t cOperations,
1930 uint32_t uTotalOperationsWeight, const char *pcszFirstOperationDescription,
1931 uint32_t uFirstOperationWeight, VBOXEXTPACK_IF_CS(IProgress) **ppProgressOut)
1932{
1933 /*
1934 * Validate the input and get our bearings.
1935 */
1936 AssertPtrReturn(pcszDescription, (uint32_t)E_INVALIDARG);
1937 AssertReturn(cOperations >= 1, (uint32_t)E_INVALIDARG);
1938 AssertReturn(uTotalOperationsWeight >= 1, (uint32_t)E_INVALIDARG);
1939 AssertPtrReturn(pcszFirstOperationDescription, (uint32_t)E_INVALIDARG);
1940 AssertReturn(uFirstOperationWeight >= 1, (uint32_t)E_INVALIDARG);
1941 AssertPtrReturn(ppProgressOut, (uint32_t)E_INVALIDARG);
1942
1943 AssertPtrReturn(pHlp, (uint32_t)E_INVALIDARG);
1944 AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, (uint32_t)E_INVALIDARG);
1945#ifndef VBOX_COM_INPROC
1946 ExtPack::Data *pData = RT_FROM_CPP_MEMBER(pHlp, Data, Hlp);
1947#endif
1948
1949 ComObjPtr<Progress> pProgress;
1950 HRESULT hrc = pProgress.createObject();
1951 if (SUCCEEDED(hrc))
1952 {
1953 hrc = pProgress->init(
1954#ifndef VBOX_COM_INPROC
1955 pData->pVirtualBox,
1956#endif
1957 pInitiator, pcszDescription, TRUE /* aCancelable */,
1958 cOperations, uTotalOperationsWeight,
1959 pcszFirstOperationDescription, uFirstOperationWeight);
1960 if (SUCCEEDED(hrc))
1961 hrc = pProgress.queryInterfaceTo(ppProgressOut);
1962 }
1963 return hrc;
1964}
1965
1966/**
1967 * @interface_method_impl{VBOXEXTPACKHLP,pfnGetCanceledProgress}
1968 */
1969/*static*/ DECLCALLBACK(uint32_t)
1970ExtPack::i_hlpGetCanceledProgress(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress,
1971 bool *pfCanceled)
1972{
1973 /*
1974 * Validate the input and get our bearings.
1975 */
1976 AssertPtrReturn(pProgress, (uint32_t)E_INVALIDARG);
1977 AssertPtrReturn(pfCanceled, (uint32_t)E_INVALIDARG);
1978
1979 AssertPtrReturn(pHlp, (uint32_t)E_INVALIDARG);
1980 AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, (uint32_t)E_INVALIDARG);
1981
1982 BOOL fCanceled = FALSE;
1983 HRESULT hrc = pProgress->COMGETTER(Canceled)(&fCanceled);
1984 *pfCanceled = !!fCanceled;
1985 return hrc;
1986}
1987
1988/**
1989 * @interface_method_impl{VBOXEXTPACKHLP,pfnUpdateProgress}
1990 */
1991/*static*/ DECLCALLBACK(uint32_t)
1992ExtPack::i_hlpUpdateProgress(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress,
1993 uint32_t uPercent)
1994{
1995 /*
1996 * Validate the input and get our bearings.
1997 */
1998 AssertPtrReturn(pProgress, (uint32_t)E_INVALIDARG);
1999 AssertReturn(uPercent <= 100, (uint32_t)E_INVALIDARG);
2000
2001 AssertPtrReturn(pHlp, (uint32_t)E_INVALIDARG);
2002 AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, (uint32_t)E_INVALIDARG);
2003
2004 ComPtr<IInternalProgressControl> pProgressControl(pProgress);
2005 AssertReturn(!!pProgressControl, (uint32_t)E_INVALIDARG);
2006 return pProgressControl->SetCurrentOperationProgress(uPercent);
2007}
2008
2009/**
2010 * @interface_method_impl{VBOXEXTPACKHLP,pfnNextOperationProgress}
2011 */
2012/*static*/ DECLCALLBACK(uint32_t)
2013ExtPack::i_hlpNextOperationProgress(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress,
2014 const char *pcszNextOperationDescription,
2015 uint32_t uNextOperationWeight)
2016{
2017 /*
2018 * Validate the input and get our bearings.
2019 */
2020 AssertPtrReturn(pProgress, (uint32_t)E_INVALIDARG);
2021 AssertPtrReturn(pcszNextOperationDescription, (uint32_t)E_INVALIDARG);
2022 AssertReturn(uNextOperationWeight >= 1, (uint32_t)E_INVALIDARG);
2023
2024 AssertPtrReturn(pHlp, (uint32_t)E_INVALIDARG);
2025 AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, (uint32_t)E_INVALIDARG);
2026
2027 ComPtr<IInternalProgressControl> pProgressControl(pProgress);
2028 AssertReturn(!!pProgressControl, (uint32_t)E_INVALIDARG);
2029 return pProgressControl->SetNextOperation(Bstr(pcszNextOperationDescription).raw(), uNextOperationWeight);
2030}
2031
2032/**
2033 * @interface_method_impl{VBOXEXTPACKHLP,pfnWaitOtherProgress}
2034 */
2035/*static*/ DECLCALLBACK(uint32_t)
2036ExtPack::i_hlpWaitOtherProgress(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress,
2037 VBOXEXTPACK_IF_CS(IProgress) *pProgressOther, uint32_t cTimeoutMS)
2038{
2039 /*
2040 * Validate the input and get our bearings.
2041 */
2042 AssertPtrReturn(pProgress, (uint32_t)E_INVALIDARG);
2043 AssertPtrReturn(pProgressOther, (uint32_t)E_INVALIDARG);
2044
2045 AssertPtrReturn(pHlp, (uint32_t)E_INVALIDARG);
2046 AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, (uint32_t)E_INVALIDARG);
2047
2048 ComPtr<IInternalProgressControl> pProgressControl(pProgress);
2049 AssertReturn(!!pProgressControl, (uint32_t)E_INVALIDARG);
2050 return pProgressControl->WaitForOtherProgressCompletion(pProgressOther, cTimeoutMS);
2051}
2052
2053/**
2054 * @interface_method_impl{VBOXEXTPACKHLP,pfnCompleteProgress}
2055 */
2056/*static*/ DECLCALLBACK(uint32_t)
2057ExtPack::i_hlpCompleteProgress(PCVBOXEXTPACKHLP pHlp, VBOXEXTPACK_IF_CS(IProgress) *pProgress,
2058 uint32_t uResultCode)
2059{
2060 /*
2061 * Validate the input and get our bearings.
2062 */
2063 AssertPtrReturn(pHlp, (uint32_t)E_INVALIDARG);
2064 AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, (uint32_t)E_INVALIDARG);
2065 AssertPtrReturn(pProgress, (uint32_t)E_INVALIDARG);
2066
2067 ComPtr<IInternalProgressControl> pProgressControl(pProgress);
2068 AssertReturn(!!pProgressControl, (uint32_t)E_INVALIDARG);
2069
2070 ComPtr<IVirtualBoxErrorInfo> errorInfo;
2071 if (FAILED((HRESULT)uResultCode))
2072 {
2073 ErrorInfoKeeper eik;
2074 eik.getVirtualBoxErrorInfo(errorInfo);
2075 }
2076 return pProgressControl->NotifyComplete((LONG)uResultCode, errorInfo);
2077}
2078
2079/**
2080 * @interface_method_impl{VBOXEXTPACKHLP,pfnCreateEvent}
2081 */
2082/*static*/ DECLCALLBACK(uint32_t)
2083ExtPack::i_hlpCreateEvent(PCVBOXEXTPACKHLP pHlp,
2084 VBOXEXTPACK_IF_CS(IEventSource) *aSource,
2085 /* VBoxEventType_T */ uint32_t aType, bool aWaitable,
2086 VBOXEXTPACK_IF_CS(IEvent) **ppEventOut)
2087{
2088 /*
2089 * Validate the input and get our bearings.
2090 */
2091 AssertPtrReturn(pHlp, (uint32_t)E_INVALIDARG);
2092 AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, (uint32_t)E_INVALIDARG);
2093 AssertPtrReturn(ppEventOut, (uint32_t)E_INVALIDARG);
2094
2095 ComObjPtr<VBoxEvent> pEvent;
2096 HRESULT hrc = pEvent.createObject();
2097 if (SUCCEEDED(hrc))
2098 {
2099 /* default aSource to pVirtualBox? */
2100 hrc = pEvent->init(aSource, static_cast<VBoxEventType_T>(aType), aWaitable);
2101 if (SUCCEEDED(hrc))
2102 hrc = pEvent.queryInterfaceTo(ppEventOut);
2103 }
2104 return hrc;
2105}
2106
2107/**
2108 * @interface_method_impl{VBOXEXTPACKHLP,pfnCreateVetoEvent}
2109 */
2110/*static*/ DECLCALLBACK(uint32_t)
2111ExtPack::i_hlpCreateVetoEvent(PCVBOXEXTPACKHLP pHlp,
2112 VBOXEXTPACK_IF_CS(IEventSource) *aSource,
2113 /* VBoxEventType_T */ uint32_t aType,
2114 VBOXEXTPACK_IF_CS(IVetoEvent) **ppEventOut)
2115{
2116 AssertPtrReturn(pHlp, (uint32_t)E_INVALIDARG);
2117 AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, (uint32_t)E_INVALIDARG);
2118 AssertPtrReturn(ppEventOut, (uint32_t)E_INVALIDARG);
2119
2120 ComObjPtr<VBoxVetoEvent> pEvent;
2121
2122 HRESULT hrc = pEvent.createObject();
2123 if (SUCCEEDED(hrc))
2124 {
2125 /* default aSource to pVirtualBox? */
2126 hrc = pEvent->init(aSource, static_cast<VBoxEventType_T>(aType));
2127 if (SUCCEEDED(hrc))
2128 hrc = pEvent.queryInterfaceTo(ppEventOut);
2129 }
2130 return hrc;
2131}
2132
2133/**
2134 * @interface_method_impl{VBOXEXTPACKHLP,pfnTranslate}
2135 */
2136/*static*/ DECLCALLBACK(const char *)
2137ExtPack::i_hlpTranslate(PCVBOXEXTPACKHLP pHlp,
2138 const char *pszComponent,
2139 const char *pszSourceText,
2140 const char *pszComment /*=NULL*/,
2141 const size_t uNum /*= ~(size_t)0*/)
2142{
2143 /*
2144 * Validate the input and get our bearings.
2145 */
2146 AssertPtrReturn(pHlp, pszSourceText);
2147 AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, pszSourceText);
2148 ExtPack::Data *pData = RT_FROM_CPP_MEMBER(pHlp, Data, Hlp);
2149 AssertPtrReturn(pData, pszSourceText);
2150
2151#ifdef VBOX_WITH_MAIN_NLS
2152 return VirtualBoxTranslator::translate(pData->pTrComponent, pszComponent, pszSourceText, pszComment, uNum);
2153#else
2154 RT_NOREF(pszComponent, pszComment, uNum);
2155 return pszSourceText;
2156#endif
2157}
2158
2159
2160/*static*/ DECLCALLBACK(int)
2161ExtPack::i_hlpReservedN(PCVBOXEXTPACKHLP pHlp)
2162{
2163 /*
2164 * Validate the input and get our bearings.
2165 */
2166 AssertPtrReturn(pHlp, VERR_INVALID_POINTER);
2167 AssertReturn(pHlp->u32Version == VBOXEXTPACKHLP_VERSION, VERR_INVALID_POINTER);
2168 ExtPack::Data *pData = RT_FROM_CPP_MEMBER(pHlp, Data, Hlp);
2169 AssertPtrReturn(pData, VERR_INVALID_POINTER);
2170 ExtPack *pThis = pData->pThis;
2171 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
2172
2173 return VERR_NOT_IMPLEMENTED;
2174}
2175
2176
2177
2178
2179HRESULT ExtPack::getName(com::Utf8Str &aName)
2180{
2181 aName = m->Desc.strName;
2182 return S_OK;
2183}
2184
2185HRESULT ExtPack::getDescription(com::Utf8Str &aDescription)
2186{
2187 aDescription = m->Desc.strDescription;
2188 return S_OK;
2189}
2190
2191HRESULT ExtPack::getVersion(com::Utf8Str &aVersion)
2192{
2193 aVersion = m->Desc.strVersion;
2194 return S_OK;
2195}
2196
2197HRESULT ExtPack::getRevision(ULONG *aRevision)
2198{
2199 *aRevision = m->Desc.uRevision;
2200 return S_OK;
2201}
2202
2203HRESULT ExtPack::getEdition(com::Utf8Str &aEdition)
2204{
2205 aEdition = m->Desc.strEdition;
2206 return S_OK;
2207}
2208
2209HRESULT ExtPack::getVRDEModule(com::Utf8Str &aVRDEModule)
2210{
2211 aVRDEModule = m->Desc.strVrdeModule;
2212 return S_OK;
2213}
2214
2215HRESULT ExtPack::getCryptoModule(com::Utf8Str &aCryptoModule)
2216{
2217 aCryptoModule = m->Desc.strCryptoModule;
2218 return S_OK;
2219}
2220
2221HRESULT ExtPack::getPlugIns(std::vector<ComPtr<IExtPackPlugIn> > &aPlugIns)
2222{
2223 /** @todo implement plug-ins. */
2224 NOREF(aPlugIns);
2225 ReturnComNotImplemented();
2226}
2227
2228HRESULT ExtPack::getUsable(BOOL *aUsable)
2229{
2230 *aUsable = m->fUsable;
2231 return S_OK;
2232}
2233
2234HRESULT ExtPack::getWhyUnusable(com::Utf8Str &aWhyUnusable)
2235{
2236 aWhyUnusable = m->strWhyUnusable;
2237 return S_OK;
2238}
2239
2240HRESULT ExtPack::getShowLicense(BOOL *aShowLicense)
2241{
2242 *aShowLicense = m->Desc.fShowLicense;
2243 return S_OK;
2244}
2245
2246HRESULT ExtPack::getLicense(com::Utf8Str &aLicense)
2247{
2248 Utf8Str strHtml("html");
2249 Utf8Str str("");
2250 return queryLicense(str, str, strHtml, aLicense);
2251}
2252
2253HRESULT ExtPack::queryLicense(const com::Utf8Str &aPreferredLocale, const com::Utf8Str &aPreferredLanguage,
2254 const com::Utf8Str &aFormat, com::Utf8Str &aLicenseText)
2255{
2256 HRESULT hrc = S_OK;
2257
2258 /*
2259 * Validate input.
2260 */
2261 if (aPreferredLocale.length() != 2 && aPreferredLocale.length() != 0)
2262 return setError(E_FAIL, tr("The preferred locale is a two character string or empty."));
2263
2264 if (aPreferredLanguage.length() != 2 && aPreferredLanguage.length() != 0)
2265 return setError(E_FAIL, tr("The preferred language is a two character string or empty."));
2266
2267 if ( !aFormat.equals("html")
2268 && !aFormat.equals("rtf")
2269 && !aFormat.equals("txt"))
2270 return setError(E_FAIL, tr("The license format can only have the values 'html', 'rtf' and 'txt'."));
2271
2272 /*
2273 * Combine the options to form a file name before locking down anything.
2274 */
2275 char szName[sizeof(VBOX_EXTPACK_LICENSE_NAME_PREFIX "-de_DE.html") + 2];
2276 if (aPreferredLocale.isNotEmpty() && aPreferredLanguage.isNotEmpty())
2277 RTStrPrintf(szName, sizeof(szName), VBOX_EXTPACK_LICENSE_NAME_PREFIX "-%s_%s.%s",
2278 aPreferredLocale.c_str(), aPreferredLanguage.c_str(), aFormat.c_str());
2279 else if (aPreferredLocale.isNotEmpty())
2280 RTStrPrintf(szName, sizeof(szName), VBOX_EXTPACK_LICENSE_NAME_PREFIX "-%s.%s",
2281 aPreferredLocale.c_str(), aFormat.c_str());
2282 else if (aPreferredLanguage.isNotEmpty())
2283 RTStrPrintf(szName, sizeof(szName), VBOX_EXTPACK_LICENSE_NAME_PREFIX "-_%s.%s",
2284 aPreferredLocale.c_str(), aFormat.c_str());
2285 else
2286 RTStrPrintf(szName, sizeof(szName), VBOX_EXTPACK_LICENSE_NAME_PREFIX ".%s",
2287 aFormat.c_str());
2288
2289 /*
2290 * Effectuate the query.
2291 */
2292 AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS); /* paranoia */
2293
2294 if (!m->fUsable)
2295 hrc = setError(E_FAIL, "%s", m->strWhyUnusable.c_str());
2296 else
2297 {
2298 char szPath[RTPATH_MAX];
2299 int vrc = RTPathJoin(szPath, sizeof(szPath), m->strExtPackPath.c_str(), szName);
2300 if (RT_SUCCESS(vrc))
2301 {
2302 void *pvFile;
2303 size_t cbFile;
2304 vrc = RTFileReadAllEx(szPath, 0, RTFOFF_MAX, RTFILE_RDALL_O_DENY_READ, &pvFile, &cbFile);
2305 if (RT_SUCCESS(vrc))
2306 {
2307 Bstr bstrLicense((const char *)pvFile, cbFile);
2308 if (bstrLicense.isNotEmpty())
2309 {
2310 aLicenseText = Utf8Str(bstrLicense);
2311 hrc = S_OK;
2312 }
2313 else
2314 hrc = setError(VBOX_E_IPRT_ERROR, tr("The license file '%s' is empty or contains invalid UTF-8 encoding"),
2315 szPath);
2316 RTFileReadAllFree(pvFile, cbFile);
2317 }
2318 else if (vrc == VERR_FILE_NOT_FOUND || vrc == VERR_PATH_NOT_FOUND)
2319 hrc = setErrorBoth(VBOX_E_OBJECT_NOT_FOUND, vrc, tr("The license file '%s' was not found in extension pack '%s'"),
2320 szName, m->Desc.strName.c_str());
2321 else
2322 hrc = setErrorBoth(VBOX_E_FILE_ERROR, vrc, tr("Failed to open the license file '%s': %Rrc"), szPath, vrc);
2323 }
2324 else
2325 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("RTPathJoin failed: %Rrc"), vrc);
2326 }
2327 return hrc;
2328}
2329
2330HRESULT ExtPack::queryObject(const com::Utf8Str &aObjUuid, ComPtr<IUnknown> &aReturnInterface)
2331{
2332 com::Guid ObjectId;
2333 CheckComArgGuid(aObjUuid, ObjectId);
2334
2335 HRESULT hrc = S_OK;
2336
2337 if ( m->pReg
2338 && m->pReg->pfnQueryObject)
2339 {
2340 void *pvUnknown = m->pReg->pfnQueryObject(m->pReg, ObjectId.raw());
2341 if (pvUnknown)
2342 {
2343 aReturnInterface = (IUnknown *)pvUnknown;
2344 /* The above assignment increased the refcount. Since pvUnknown
2345 * is a dumb pointer we have to do the release ourselves. */
2346 ((IUnknown *)pvUnknown)->Release();
2347 }
2348 else
2349 hrc = E_NOINTERFACE;
2350 }
2351 else
2352 hrc = E_NOINTERFACE;
2353 return hrc;
2354}
2355
2356DEFINE_EMPTY_CTOR_DTOR(ExtPackManager)
2357
2358/**
2359 * Called by ComObjPtr::createObject when creating the object.
2360 *
2361 * Just initialize the basic object state, do the rest in init().
2362 *
2363 * @returns S_OK.
2364 */
2365HRESULT ExtPackManager::FinalConstruct()
2366{
2367 m = NULL;
2368 return BaseFinalConstruct();
2369}
2370
2371/**
2372 * Initializes the extension pack manager.
2373 *
2374 * @returns COM status code.
2375 * @param a_pVirtualBox Pointer to the VirtualBox object.
2376 * @param a_enmContext The context we're in.
2377 */
2378HRESULT ExtPackManager::initExtPackManager(VirtualBox *a_pVirtualBox, VBOXEXTPACKCTX a_enmContext)
2379{
2380 AutoInitSpan autoInitSpan(this);
2381 AssertReturn(autoInitSpan.isOk(), E_FAIL);
2382
2383 /*
2384 * Figure some stuff out before creating the instance data.
2385 */
2386 char szBaseDir[RTPATH_MAX];
2387 int vrc = RTPathAppPrivateArchTop(szBaseDir, sizeof(szBaseDir));
2388 AssertLogRelRCReturn(vrc, E_FAIL);
2389 vrc = RTPathAppend(szBaseDir, sizeof(szBaseDir), VBOX_EXTPACK_INSTALL_DIR);
2390 AssertLogRelRCReturn(vrc, E_FAIL);
2391
2392 char szCertificatDir[RTPATH_MAX];
2393 vrc = RTPathAppPrivateNoArch(szCertificatDir, sizeof(szCertificatDir));
2394 AssertLogRelRCReturn(vrc, E_FAIL);
2395 vrc = RTPathAppend(szCertificatDir, sizeof(szCertificatDir), VBOX_EXTPACK_CERT_DIR);
2396 AssertLogRelRCReturn(vrc, E_FAIL);
2397
2398 /*
2399 * Allocate and initialize the instance data.
2400 */
2401 m = new Data;
2402 m->strBaseDir = szBaseDir;
2403 m->strCertificatDirPath = szCertificatDir;
2404 m->enmContext = a_enmContext;
2405#ifndef VBOX_COM_INPROC
2406 m->pVirtualBox = a_pVirtualBox;
2407#else
2408 RT_NOREF_PV(a_pVirtualBox);
2409#endif
2410
2411 /*
2412 * Go looking for extensions. The RTDirOpen may fail if nothing has been
2413 * installed yet, or if root is paranoid and has revoked our access to them.
2414 *
2415 * We ASSUME that there are no files, directories or stuff in the directory
2416 * that exceed the max name length in RTDIRENTRYEX.
2417 */
2418 HRESULT hrc = S_OK;
2419 RTDIR hDir;
2420 vrc = RTDirOpen(&hDir, szBaseDir);
2421 if (RT_SUCCESS(vrc))
2422 {
2423 for (;;)
2424 {
2425 RTDIRENTRYEX Entry;
2426 vrc = RTDirReadEx(hDir, &Entry, NULL /*pcbDirEntry*/, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
2427 if (RT_FAILURE(vrc))
2428 {
2429 AssertLogRelMsg(vrc == VERR_NO_MORE_FILES, ("%Rrc\n", vrc));
2430 break;
2431 }
2432 if ( RTFS_IS_DIRECTORY(Entry.Info.Attr.fMode)
2433 && strcmp(Entry.szName, ".") != 0
2434 && strcmp(Entry.szName, "..") != 0
2435 && VBoxExtPackIsValidMangledName(Entry.szName) )
2436 {
2437 /*
2438 * All directories are extensions, the shall be nothing but
2439 * extensions in this subdirectory.
2440 */
2441 char szExtPackDir[RTPATH_MAX];
2442 vrc = RTPathJoin(szExtPackDir, sizeof(szExtPackDir), m->strBaseDir.c_str(), Entry.szName);
2443 AssertLogRelRC(vrc);
2444 if (RT_SUCCESS(vrc))
2445 {
2446 RTCString *pstrName = VBoxExtPackUnmangleName(Entry.szName, RTSTR_MAX);
2447 AssertLogRel(pstrName);
2448 if (pstrName)
2449 {
2450 ComObjPtr<ExtPack> NewExtPack;
2451 HRESULT hrc2 = NewExtPack.createObject();
2452 if (SUCCEEDED(hrc2))
2453 hrc2 = NewExtPack->initWithDir(a_pVirtualBox, a_enmContext, pstrName->c_str(), szExtPackDir);
2454 delete pstrName;
2455 if (SUCCEEDED(hrc2))
2456 {
2457 m->llInstalledExtPacks.push_back(NewExtPack);
2458 /* Paranoia, there should be no API clients before this method is finished. */
2459
2460 m->cUpdate++;
2461 }
2462 else if (SUCCEEDED(hrc))
2463 hrc = hrc2;
2464 }
2465 else
2466 hrc = E_UNEXPECTED;
2467 }
2468 else
2469 hrc = E_UNEXPECTED;
2470 }
2471 }
2472 RTDirClose(hDir);
2473 }
2474 /* else: ignore, the directory probably does not exist or something. */
2475
2476 if (SUCCEEDED(hrc))
2477 autoInitSpan.setSucceeded();
2478 return hrc;
2479}
2480
2481/**
2482 * COM cruft.
2483 */
2484void ExtPackManager::FinalRelease()
2485{
2486 uninit();
2487 BaseFinalRelease();
2488}
2489
2490/**
2491 * Do the actual cleanup.
2492 */
2493void ExtPackManager::uninit()
2494{
2495 /* Enclose the state transition Ready->InUninit->NotReady */
2496 AutoUninitSpan autoUninitSpan(this);
2497 if (!autoUninitSpan.uninitDone() && m != NULL)
2498 {
2499 delete m;
2500 m = NULL;
2501 }
2502}
2503
2504HRESULT ExtPackManager::getInstalledExtPacks(std::vector<ComPtr<IExtPack> > &aInstalledExtPacks)
2505{
2506 Assert(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON);
2507
2508 AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
2509
2510 aInstalledExtPacks.resize(m->llInstalledExtPacks.size());
2511 std::copy(m->llInstalledExtPacks.begin(), m->llInstalledExtPacks.end(), aInstalledExtPacks.begin());
2512
2513 return S_OK;
2514}
2515
2516HRESULT ExtPackManager::find(const com::Utf8Str &aName, ComPtr<IExtPack> &aReturnData)
2517{
2518 HRESULT hrc = S_OK;
2519
2520 Assert(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON);
2521
2522 AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
2523
2524 ComPtr<ExtPack> ptrExtPack = i_findExtPack(aName.c_str());
2525 if (!ptrExtPack.isNull())
2526 ptrExtPack.queryInterfaceTo(aReturnData.asOutParam());
2527 else
2528 hrc = VBOX_E_OBJECT_NOT_FOUND;
2529
2530 return hrc;
2531}
2532
2533HRESULT ExtPackManager::openExtPackFile(const com::Utf8Str &aPath, ComPtr<IExtPackFile> &aFile)
2534{
2535 AssertReturn(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON, E_UNEXPECTED);
2536
2537#ifndef VBOX_COM_INPROC
2538 /* The API can optionally take a ::SHA-256=<hex-digest> attribute at the
2539 end of the file name. This is just a temporary measure for
2540 backporting, in 4.2 we'll add another parameter to the method. */
2541 Utf8Str strTarball;
2542 Utf8Str strDigest;
2543 size_t offSha256 = aPath.find("::SHA-256=");
2544 if (offSha256 == Utf8Str::npos)
2545 strTarball = aPath;
2546 else
2547 {
2548 strTarball = aPath.substr(0, offSha256);
2549 strDigest = aPath.substr(offSha256 + sizeof("::SHA-256=") - 1);
2550 }
2551
2552 ComObjPtr<ExtPackFile> NewExtPackFile;
2553 HRESULT hrc = NewExtPackFile.createObject();
2554 if (SUCCEEDED(hrc))
2555 hrc = NewExtPackFile->initWithFile(strTarball.c_str(), strDigest.c_str(), this, m->pVirtualBox);
2556 if (SUCCEEDED(hrc))
2557 NewExtPackFile.queryInterfaceTo(aFile.asOutParam());
2558
2559 return hrc;
2560#else
2561 RT_NOREF(aPath, aFile);
2562 return E_NOTIMPL;
2563#endif
2564}
2565
2566HRESULT ExtPackManager::uninstall(const com::Utf8Str &aName, BOOL aForcedRemoval,
2567 const com::Utf8Str &aDisplayInfo, ComPtr<IProgress> &aProgress)
2568{
2569 Assert(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON);
2570
2571#ifndef VBOX_COM_INPROC
2572
2573 HRESULT hrc;
2574 ExtPackUninstallTask *pTask = NULL;
2575 try
2576 {
2577 pTask = new ExtPackUninstallTask();
2578 hrc = pTask->Init(this, aName, aForcedRemoval != FALSE, aDisplayInfo);
2579 if (SUCCEEDED(hrc))
2580 {
2581 ComPtr<Progress> ptrProgress = pTask->ptrProgress;
2582 hrc = pTask->createThreadWithType(RTTHREADTYPE_DEFAULT);
2583 pTask = NULL; /* always consumed by createThread */
2584 if (SUCCEEDED(hrc))
2585 hrc = ptrProgress.queryInterfaceTo(aProgress.asOutParam());
2586 else
2587 hrc = setError(VBOX_E_IPRT_ERROR,
2588 tr("Starting thread for an extension pack uninstallation failed with %Rrc"), hrc);
2589 }
2590 else
2591 hrc = setError(hrc, tr("Looks like creating a progress object for ExtraPackUninstallTask object failed"));
2592 }
2593 catch (std::bad_alloc &)
2594 {
2595 hrc = E_OUTOFMEMORY;
2596 }
2597 catch (HRESULT hrcXcpt)
2598 {
2599 LogFlowThisFunc(("Exception was caught in the function ExtPackManager::uninstall()\n"));
2600 hrc = hrcXcpt;
2601 }
2602 if (pTask)
2603 delete pTask;
2604 return hrc;
2605#else
2606 RT_NOREF(aName, aForcedRemoval, aDisplayInfo, aProgress);
2607 return E_NOTIMPL;
2608#endif
2609}
2610
2611HRESULT ExtPackManager::cleanup(void)
2612{
2613 Assert(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON);
2614
2615 AutoCaller autoCaller(this);
2616 HRESULT hrc = autoCaller.hrc();
2617 if (SUCCEEDED(hrc))
2618 {
2619 /*
2620 * Run the set-uid-to-root binary that performs the cleanup.
2621 *
2622 * Take the write lock to prevent conflicts with other calls to this
2623 * VBoxSVC instance.
2624 */
2625 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS);
2626 hrc = i_runSetUidToRootHelper(NULL,
2627 "cleanup",
2628 "--base-dir", m->strBaseDir.c_str(),
2629 (const char *)NULL);
2630 }
2631
2632 return hrc;
2633}
2634
2635HRESULT ExtPackManager::queryAllPlugInsForFrontend(const com::Utf8Str &aFrontendName, std::vector<com::Utf8Str> &aPlugInModules)
2636{
2637 NOREF(aFrontendName);
2638 aPlugInModules.resize(0);
2639 return S_OK;
2640}
2641
2642HRESULT ExtPackManager::isExtPackUsable(const com::Utf8Str &aName, BOOL *aUsable)
2643{
2644 *aUsable = i_isExtPackUsable(aName.c_str());
2645 return S_OK;
2646}
2647
2648/**
2649 * Finds the success indicator string in the stderr output ofr hte helper app.
2650 *
2651 * @returns Pointer to the indicator.
2652 * @param psz The stderr output string. Can be NULL.
2653 * @param cch The size of the string.
2654 */
2655static char *findSuccessIndicator(char *psz, size_t cch)
2656{
2657 static const char s_szSuccessInd[] = "rcExit=RTEXITCODE_SUCCESS";
2658 Assert(!cch || strlen(psz) == cch);
2659 if (cch < sizeof(s_szSuccessInd) - 1)
2660 return NULL;
2661 char *pszInd = &psz[cch - sizeof(s_szSuccessInd) + 1];
2662 if (strcmp(s_szSuccessInd, pszInd))
2663 return NULL;
2664 return pszInd;
2665}
2666
2667/**
2668 * Runs the helper application that does the privileged operations.
2669 *
2670 * @returns S_OK or a failure status with error information set.
2671 * @param a_pstrDisplayInfo Platform specific display info hacks.
2672 * @param a_pszCommand The command to execute.
2673 * @param ... The argument strings that goes along with the
2674 * command. Maximum is about 16. Terminated by a
2675 * NULL.
2676 */
2677HRESULT ExtPackManager::i_runSetUidToRootHelper(Utf8Str const *a_pstrDisplayInfo, const char *a_pszCommand, ...)
2678{
2679 /*
2680 * Calculate the path to the helper application.
2681 */
2682 char szExecName[RTPATH_MAX];
2683 int vrc = RTPathAppPrivateArch(szExecName, sizeof(szExecName));
2684 AssertLogRelRCReturn(vrc, E_UNEXPECTED);
2685
2686 vrc = RTPathAppend(szExecName, sizeof(szExecName), VBOX_EXTPACK_HELPER_NAME);
2687 AssertLogRelRCReturn(vrc, E_UNEXPECTED);
2688
2689 /*
2690 * Convert the variable argument list to a RTProcCreate argument vector.
2691 */
2692 const char *apszArgs[20];
2693 unsigned cArgs = 0;
2694
2695 LogRel(("ExtPack: Executing '%s'", szExecName));
2696 apszArgs[cArgs++] = &szExecName[0];
2697
2698 if ( a_pstrDisplayInfo
2699 && a_pstrDisplayInfo->isNotEmpty())
2700 {
2701 LogRel((" '--display-info-hack' '%s'", a_pstrDisplayInfo->c_str()));
2702 apszArgs[cArgs++] = "--display-info-hack";
2703 apszArgs[cArgs++] = a_pstrDisplayInfo->c_str();
2704 }
2705
2706 LogRel((" '%s'", a_pszCommand));
2707 apszArgs[cArgs++] = a_pszCommand;
2708
2709 HRESULT hrc = S_OK;
2710
2711 va_list va;
2712 va_start(va, a_pszCommand);
2713 const char *pszLastArg;
2714 for (;;)
2715 {
2716 AssertBreakStmt(cArgs < RT_ELEMENTS(apszArgs) - 1, hrc = E_UNEXPECTED);
2717 pszLastArg = va_arg(va, const char *);
2718 if (!pszLastArg)
2719 break;
2720 LogRel((" '%s'", pszLastArg));
2721 apszArgs[cArgs++] = pszLastArg;
2722 };
2723 va_end(va);
2724 ComAssertComRCRet(hrc, hrc);
2725
2726 LogRel(("\n"));
2727 apszArgs[cArgs] = NULL;
2728
2729 /*
2730 * Create a PIPE which we attach to stderr so that we can read the error
2731 * message on failure and report it back to the caller.
2732 */
2733 RTPIPE hPipeR;
2734 RTHANDLE hStdErrPipe;
2735 hStdErrPipe.enmType = RTHANDLETYPE_PIPE;
2736 vrc = RTPipeCreate(&hPipeR, &hStdErrPipe.u.hPipe, RTPIPE_C_INHERIT_WRITE);
2737 AssertLogRelRCReturn(vrc, E_UNEXPECTED);
2738
2739 /*
2740 * Spawn the process.
2741 */
2742 RTPROCESS hProcess;
2743 vrc = RTProcCreateEx(szExecName,
2744 apszArgs,
2745 RTENV_DEFAULT,
2746 0 /*fFlags*/,
2747 NULL /*phStdIn*/,
2748 NULL /*phStdOut*/,
2749 &hStdErrPipe,
2750 NULL /*pszAsUser*/,
2751 NULL /*pszPassword*/,
2752 NULL /*pvExtraData*/,
2753 &hProcess);
2754 if (RT_SUCCESS(vrc))
2755 {
2756 vrc = RTPipeClose(hStdErrPipe.u.hPipe);
2757 AssertRC(vrc);
2758 hStdErrPipe.u.hPipe = NIL_RTPIPE;
2759
2760 /*
2761 * Read the pipe output until the process completes.
2762 */
2763 RTPROCSTATUS ProcStatus = { -42, RTPROCEXITREASON_ABEND };
2764 size_t cbStdErrBuf = 0;
2765 size_t offStdErrBuf = 0;
2766 char *pszStdErrBuf = NULL;
2767 do
2768 {
2769 /*
2770 * Service the pipe. Block waiting for output or the pipe breaking
2771 * when the process terminates.
2772 */
2773 if (hPipeR != NIL_RTPIPE)
2774 {
2775 char achBuf[1024];
2776 size_t cbRead;
2777 vrc = RTPipeReadBlocking(hPipeR, achBuf, sizeof(achBuf), &cbRead);
2778 if (RT_SUCCESS(vrc))
2779 {
2780 /* grow the buffer? */
2781 size_t cbBufReq = offStdErrBuf + cbRead + 1;
2782 if ( cbBufReq > cbStdErrBuf
2783 && cbBufReq < _256K)
2784 {
2785 size_t cbNew = RT_ALIGN_Z(cbBufReq, 16); // 1024
2786 void *pvNew = RTMemRealloc(pszStdErrBuf, cbNew);
2787 if (pvNew)
2788 {
2789 pszStdErrBuf = (char *)pvNew;
2790 cbStdErrBuf = cbNew;
2791 }
2792 }
2793
2794 /* append if we've got room. */
2795 if (cbBufReq <= cbStdErrBuf)
2796 {
2797 memcpy(&pszStdErrBuf[offStdErrBuf], achBuf, cbRead);
2798 offStdErrBuf = offStdErrBuf + cbRead;
2799 pszStdErrBuf[offStdErrBuf] = '\0';
2800 }
2801 }
2802 else
2803 {
2804 AssertLogRelMsg(vrc == VERR_BROKEN_PIPE, ("%Rrc\n", vrc));
2805 RTPipeClose(hPipeR);
2806 hPipeR = NIL_RTPIPE;
2807 }
2808 }
2809
2810 /*
2811 * Service the process. Block if we have no pipe.
2812 */
2813 if (hProcess != NIL_RTPROCESS)
2814 {
2815 vrc = RTProcWait(hProcess,
2816 hPipeR == NIL_RTPIPE ? RTPROCWAIT_FLAGS_BLOCK : RTPROCWAIT_FLAGS_NOBLOCK,
2817 &ProcStatus);
2818 if (RT_SUCCESS(vrc))
2819 hProcess = NIL_RTPROCESS;
2820 else
2821 AssertLogRelMsgStmt(vrc == VERR_PROCESS_RUNNING, ("%Rrc\n", vrc), hProcess = NIL_RTPROCESS);
2822 }
2823 } while ( hPipeR != NIL_RTPIPE
2824 || hProcess != NIL_RTPROCESS);
2825
2826 LogRel(("ExtPack: enmReason=%d iStatus=%d stderr='%s'\n",
2827 ProcStatus.enmReason, ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : ""));
2828
2829 /*
2830 * Look for rcExit=RTEXITCODE_SUCCESS at the end of the error output,
2831 * cut it as it is only there to attest the success.
2832 */
2833 if (offStdErrBuf > 0)
2834 {
2835 RTStrStripR(pszStdErrBuf);
2836 offStdErrBuf = strlen(pszStdErrBuf);
2837 }
2838
2839 char *pszSuccessInd = findSuccessIndicator(pszStdErrBuf, offStdErrBuf);
2840 if (pszSuccessInd)
2841 {
2842 *pszSuccessInd = '\0';
2843 offStdErrBuf = (size_t)(pszSuccessInd - pszStdErrBuf);
2844 }
2845 else if ( ProcStatus.enmReason == RTPROCEXITREASON_NORMAL
2846 && ProcStatus.iStatus == 0)
2847 ProcStatus.iStatus = offStdErrBuf ? 667 : 666;
2848
2849 /*
2850 * Compose the status code and, on failure, error message.
2851 */
2852 if ( ProcStatus.enmReason == RTPROCEXITREASON_NORMAL
2853 && ProcStatus.iStatus == 0)
2854 hrc = S_OK;
2855 else if (ProcStatus.enmReason == RTPROCEXITREASON_NORMAL)
2856 {
2857 AssertMsg(ProcStatus.iStatus != 0, ("%s\n", pszStdErrBuf));
2858 hrc = setError(E_FAIL, tr("The installer failed with exit code %d: %s"),
2859 ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : "");
2860 }
2861 else if (ProcStatus.enmReason == RTPROCEXITREASON_SIGNAL)
2862 hrc = setError(E_UNEXPECTED, tr("The installer was killed by signal #d (stderr: %s)"),
2863 ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : "");
2864 else if (ProcStatus.enmReason == RTPROCEXITREASON_ABEND)
2865 hrc = setError(E_UNEXPECTED, tr("The installer aborted abnormally (stderr: %s)"),
2866 offStdErrBuf ? pszStdErrBuf : "");
2867 else
2868 hrc = setError(E_UNEXPECTED, tr("internal error: enmReason=%d iStatus=%d stderr='%s'"),
2869 ProcStatus.enmReason, ProcStatus.iStatus, offStdErrBuf ? pszStdErrBuf : "");
2870
2871 RTMemFree(pszStdErrBuf);
2872 }
2873 else
2874 hrc = setErrorBoth(VBOX_E_IPRT_ERROR, vrc, tr("Failed to launch the helper application '%s' (%Rrc)"), szExecName, vrc);
2875
2876 RTPipeClose(hPipeR);
2877 RTPipeClose(hStdErrPipe.u.hPipe);
2878
2879 return hrc;
2880}
2881
2882/**
2883 * Finds an installed extension pack.
2884 *
2885 * @returns Pointer to the extension pack if found, NULL if not. (No reference
2886 * counting problem here since the caller must be holding the lock.)
2887 * @param a_pszName The name of the extension pack.
2888 */
2889ExtPack *ExtPackManager::i_findExtPack(const char *a_pszName)
2890{
2891 size_t cchName = strlen(a_pszName);
2892
2893 for (ExtPackList::iterator it = m->llInstalledExtPacks.begin();
2894 it != m->llInstalledExtPacks.end();
2895 ++it)
2896 {
2897 ExtPack::Data *pExtPackData = (*it)->m;
2898 if ( pExtPackData
2899 && pExtPackData->Desc.strName.length() == cchName
2900 && pExtPackData->Desc.strName.equalsIgnoreCase(a_pszName))
2901 return (*it);
2902 }
2903 return NULL;
2904}
2905
2906/**
2907 * Removes an installed extension pack from the internal list.
2908 *
2909 * The package is expected to exist!
2910 *
2911 * @param a_pszName The name of the extension pack.
2912 */
2913void ExtPackManager::i_removeExtPack(const char *a_pszName)
2914{
2915 size_t cchName = strlen(a_pszName);
2916
2917 for (ExtPackList::iterator it = m->llInstalledExtPacks.begin();
2918 it != m->llInstalledExtPacks.end();
2919 ++it)
2920 {
2921 ExtPack::Data *pExtPackData = (*it)->m;
2922 if ( pExtPackData
2923 && pExtPackData->Desc.strName.length() == cchName
2924 && pExtPackData->Desc.strName.equalsIgnoreCase(a_pszName))
2925 {
2926 m->llInstalledExtPacks.erase(it);
2927 m->cUpdate++;
2928 return;
2929 }
2930 }
2931 AssertMsgFailed(("%s\n", a_pszName));
2932}
2933
2934#ifndef VBOX_COM_INPROC
2935
2936/**
2937 * Refreshes the specified extension pack.
2938 *
2939 * This may remove the extension pack from the list, so any non-smart pointers
2940 * to the extension pack object may become invalid.
2941 *
2942 * @returns S_OK and *a_ppExtPack on success, COM status code and error
2943 * message on failure. Note that *a_ppExtPack can be NULL.
2944 *
2945 * @param a_pszName The extension to update..
2946 * @param a_fUnusableIsError If @c true, report an unusable extension pack
2947 * as an error.
2948 * @param a_ppExtPack Where to store the pointer to the extension
2949 * pack of it is still around after the refresh.
2950 * This is optional.
2951 *
2952 * @remarks Caller holds the extension manager lock.
2953 * @remarks Only called in VBoxSVC.
2954 */
2955HRESULT ExtPackManager::i_refreshExtPack(const char *a_pszName, bool a_fUnusableIsError, ExtPack **a_ppExtPack)
2956{
2957 Assert(m->pVirtualBox != NULL); /* Only called from VBoxSVC. */
2958
2959 HRESULT hrc;
2960 ExtPack *pExtPack = i_findExtPack(a_pszName);
2961 if (pExtPack)
2962 {
2963 /*
2964 * Refresh existing object.
2965 */
2966 bool fCanDelete;
2967 hrc = pExtPack->i_refresh(&fCanDelete);
2968 if (SUCCEEDED(hrc))
2969 {
2970 if (fCanDelete)
2971 {
2972 i_removeExtPack(a_pszName);
2973 pExtPack = NULL;
2974 }
2975 }
2976 }
2977 else
2978 {
2979 /*
2980 * Do this check here, otherwise VBoxExtPackCalcDir() will fail with a strange
2981 * error.
2982 */
2983 bool fValid = VBoxExtPackIsValidName(a_pszName);
2984 if (!fValid)
2985 return setError(E_FAIL, "Invalid extension pack name specified");
2986
2987 /*
2988 * Does the dir exist? Make some special effort to deal with case
2989 * sensitivie file systems (a_pszName is case insensitive and mangled).
2990 */
2991 char szDir[RTPATH_MAX];
2992 int vrc = VBoxExtPackCalcDir(szDir, sizeof(szDir), m->strBaseDir.c_str(), a_pszName);
2993 AssertLogRelRCReturn(vrc, E_FAIL);
2994
2995 RTDIRENTRYEX Entry;
2996 RTFSOBJINFO ObjInfo;
2997 vrc = RTPathQueryInfoEx(szDir, &ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
2998 bool fExists = RT_SUCCESS(vrc) && RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode);
2999 if (!fExists)
3000 {
3001 RTDIR hDir;
3002 vrc = RTDirOpen(&hDir, m->strBaseDir.c_str());
3003 if (RT_SUCCESS(vrc))
3004 {
3005 const char *pszMangledName = RTPathFilename(szDir);
3006 for (;;)
3007 {
3008 vrc = RTDirReadEx(hDir, &Entry, NULL /*pcbDirEntry*/, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
3009 if (RT_FAILURE(vrc))
3010 {
3011 AssertLogRelMsg(vrc == VERR_NO_MORE_FILES, ("%Rrc\n", vrc));
3012 break;
3013 }
3014 if ( RTFS_IS_DIRECTORY(Entry.Info.Attr.fMode)
3015 && !RTStrICmp(Entry.szName, pszMangledName))
3016 {
3017 /*
3018 * The installed extension pack has a uses different case.
3019 * Update the name and directory variables.
3020 */
3021 vrc = RTPathJoin(szDir, sizeof(szDir), m->strBaseDir.c_str(), Entry.szName); /* not really necessary */
3022 AssertLogRelRCReturnStmt(vrc, RTDirClose(hDir), E_UNEXPECTED);
3023 a_pszName = Entry.szName;
3024 fExists = true;
3025 break;
3026 }
3027 }
3028 RTDirClose(hDir);
3029 }
3030 }
3031 if (fExists)
3032 {
3033 /*
3034 * We've got something, create a new extension pack object for it.
3035 */
3036 ComObjPtr<ExtPack> ptrNewExtPack;
3037 hrc = ptrNewExtPack.createObject();
3038 if (SUCCEEDED(hrc))
3039 hrc = ptrNewExtPack->initWithDir(m->pVirtualBox, m->enmContext, a_pszName, szDir);
3040 if (SUCCEEDED(hrc))
3041 {
3042 m->llInstalledExtPacks.push_back(ptrNewExtPack);
3043 m->cUpdate++;
3044 if (ptrNewExtPack->m->fUsable)
3045 LogRel(("ExtPackManager: Found extension pack '%s'.\n", a_pszName));
3046 else
3047 LogRel(("ExtPackManager: Found bad extension pack '%s': %s\n",
3048 a_pszName, ptrNewExtPack->m->strWhyUnusable.c_str() ));
3049 pExtPack = ptrNewExtPack;
3050 }
3051 }
3052 else
3053 hrc = S_OK;
3054 }
3055
3056 /*
3057 * Report error if not usable, if that is desired.
3058 */
3059 if ( SUCCEEDED(hrc)
3060 && pExtPack
3061 && a_fUnusableIsError
3062 && !pExtPack->m->fUsable)
3063 hrc = setError(E_FAIL, "%s", pExtPack->m->strWhyUnusable.c_str());
3064
3065 if (a_ppExtPack)
3066 *a_ppExtPack = pExtPack;
3067 return hrc;
3068}
3069
3070/**
3071 * Checks if there are any running VMs.
3072 *
3073 * This is called when uninstalling or replacing an extension pack.
3074 *
3075 * @returns true / false
3076 */
3077bool ExtPackManager::i_areThereAnyRunningVMs(void) const
3078{
3079 Assert(m->pVirtualBox != NULL); /* Only called from VBoxSVC. */
3080
3081 /*
3082 * Get list of machines and their states.
3083 */
3084 com::SafeIfaceArray<IMachine> SaMachines;
3085 HRESULT hrc = m->pVirtualBox->COMGETTER(Machines)(ComSafeArrayAsOutParam(SaMachines));
3086 if (SUCCEEDED(hrc))
3087 {
3088 com::SafeArray<MachineState_T> SaStates;
3089 hrc = m->pVirtualBox->GetMachineStates(ComSafeArrayAsInParam(SaMachines), ComSafeArrayAsOutParam(SaStates));
3090 if (SUCCEEDED(hrc))
3091 {
3092 /*
3093 * Scan the two parallel arrays for machines in the running state.
3094 */
3095 Assert(SaStates.size() == SaMachines.size());
3096 for (size_t i = 0; i < SaMachines.size(); ++i)
3097 if (SaMachines[i] && Global::IsOnline(SaStates[i]))
3098 return true;
3099 }
3100 }
3101 return false;
3102}
3103
3104/**
3105 * Worker for IExtPackFile::Install.
3106 *
3107 * Called on a worker thread via doInstallThreadProc.
3108 *
3109 * @returns COM status code.
3110 * @param a_pExtPackFile The extension pack file, caller checks that
3111 * it's usable.
3112 * @param a_fReplace Whether to replace any existing extpack or just
3113 * fail.
3114 * @param a_pstrDisplayInfo Host specific display information hacks.
3115 * be NULL.
3116 */
3117HRESULT ExtPackManager::i_doInstall(ExtPackFile *a_pExtPackFile, bool a_fReplace, Utf8Str const *a_pstrDisplayInfo)
3118{
3119 AssertReturn(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON, E_UNEXPECTED);
3120 RTCString const * const pStrName = &a_pExtPackFile->m->Desc.strName;
3121 RTCString const * const pStrTarball = &a_pExtPackFile->m->strExtPackFile;
3122 RTCString const * const pStrTarballDigest = &a_pExtPackFile->m->strDigest;
3123
3124 AutoCaller autoCaller(this);
3125 HRESULT hrc = autoCaller.hrc();
3126 if (SUCCEEDED(hrc))
3127 {
3128 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3129
3130 /*
3131 * Refresh the data we have on the extension pack as it
3132 * may be made stale by direct meddling or some other user.
3133 */
3134 ExtPack *pExtPack;
3135 hrc = i_refreshExtPack(pStrName->c_str(), false /*a_fUnusableIsError*/, &pExtPack);
3136 if (SUCCEEDED(hrc))
3137 {
3138 if (pExtPack && a_fReplace)
3139 {
3140 /* We must leave the lock when calling i_areThereAnyRunningVMs,
3141 which means we have to redo the refresh call afterwards. */
3142 autoLock.release();
3143 bool fRunningVMs = i_areThereAnyRunningVMs();
3144 bool fVetoingCP = pExtPack->i_areThereCloudProviderUninstallVetos();
3145 bool fUnloadedCryptoMod = m->pVirtualBox->i_unloadCryptoIfModule() == S_OK;
3146 autoLock.acquire();
3147 hrc = i_refreshExtPack(pStrName->c_str(), false /*a_fUnusableIsError*/, &pExtPack);
3148 if (fRunningVMs)
3149 {
3150 LogRel(("Upgrading extension pack '%s' failed because at least one VM is still running.", pStrName->c_str()));
3151 hrc = setError(E_FAIL, tr("Upgrading extension pack '%s' failed because at least one VM is still running"),
3152 pStrName->c_str());
3153 }
3154 else if (fVetoingCP)
3155 {
3156 LogRel(("Upgrading extension pack '%s' failed because at least one Cloud Provider is still busy.", pStrName->c_str()));
3157 hrc = setError(E_FAIL, tr("Upgrading extension pack '%s' failed because at least one Cloud Provider is still busy"),
3158 pStrName->c_str());
3159 }
3160 else if (!fUnloadedCryptoMod)
3161 {
3162 LogRel(("Upgrading extension pack '%s' failed because the cryptographic support module is still in use.", pStrName->c_str()));
3163 hrc = setError(E_FAIL, tr("Upgrading extension pack '%s' failed because the cryptographic support module is still in use"),
3164 pStrName->c_str());
3165 }
3166 else if (SUCCEEDED(hrc) && pExtPack)
3167 hrc = pExtPack->i_callUninstallHookAndClose(m->pVirtualBox, false /*a_ForcedRemoval*/);
3168 }
3169 else if (pExtPack)
3170 hrc = setError(E_FAIL,
3171 tr("Extension pack '%s' is already installed."
3172 " In case of a reinstallation, please uninstall it first"),
3173 pStrName->c_str());
3174 }
3175 if (SUCCEEDED(hrc))
3176 {
3177 /*
3178 * Run the privileged helper binary that performs the actual
3179 * installation. Then create an object for the packet (we do this
3180 * even on failure, to be on the safe side).
3181 */
3182 hrc = i_runSetUidToRootHelper(a_pstrDisplayInfo,
3183 "install",
3184 "--base-dir", m->strBaseDir.c_str(),
3185 "--cert-dir", m->strCertificatDirPath.c_str(),
3186 "--name", pStrName->c_str(),
3187 "--tarball", pStrTarball->c_str(),
3188 "--sha-256", pStrTarballDigest->c_str(),
3189 pExtPack ? "--replace" : (const char *)NULL,
3190 (const char *)NULL);
3191 if (SUCCEEDED(hrc))
3192 {
3193 hrc = i_refreshExtPack(pStrName->c_str(), true /*a_fUnusableIsError*/, &pExtPack);
3194 if (SUCCEEDED(hrc) && pExtPack)
3195 {
3196 RTERRINFOSTATIC ErrInfo;
3197 RTErrInfoInitStatic(&ErrInfo);
3198 pExtPack->i_callInstalledHook(m->pVirtualBox, &autoLock, &ErrInfo.Core);
3199 if (RT_SUCCESS(ErrInfo.Core.rc))
3200 {
3201 LogRel(("ExtPackManager: Successfully installed extension pack '%s'.\n", pStrName->c_str()));
3202 m->pVirtualBox->i_onExtPackInstalled(*pStrName);
3203 }
3204 else
3205 {
3206 LogRel(("ExtPackManager: Installed hook for '%s' failed: %Rrc - %s\n",
3207 pStrName->c_str(), ErrInfo.Core.rc, ErrInfo.Core.pszMsg));
3208
3209 /*
3210 * Uninstall the extpack if the error indicates that.
3211 */
3212 if (ErrInfo.Core.rc == VERR_EXTPACK_UNSUPPORTED_HOST_UNINSTALL)
3213 i_runSetUidToRootHelper(a_pstrDisplayInfo,
3214 "uninstall",
3215 "--base-dir", m->strBaseDir.c_str(),
3216 "--name", pStrName->c_str(),
3217 "--forced",
3218 (const char *)NULL);
3219 hrc = setErrorBoth(E_FAIL, ErrInfo.Core.rc, tr("The installation hook failed: %Rrc - %s"),
3220 ErrInfo.Core.rc, ErrInfo.Core.pszMsg);
3221 }
3222 }
3223 else if (SUCCEEDED(hrc))
3224 hrc = setError(E_FAIL, tr("Installing extension pack '%s' failed under mysterious circumstances"),
3225 pStrName->c_str());
3226 }
3227 else
3228 {
3229 ErrorInfoKeeper Eik;
3230 i_refreshExtPack(pStrName->c_str(), false /*a_fUnusableIsError*/, NULL);
3231 }
3232 }
3233
3234 /*
3235 * Do VirtualBoxReady callbacks now for any freshly installed
3236 * extension pack (old ones will not be called).
3237 */
3238 if (m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON)
3239 {
3240 autoLock.release();
3241 i_callAllVirtualBoxReadyHooks();
3242 }
3243 }
3244
3245 return hrc;
3246}
3247
3248/**
3249 * Worker for IExtPackManager::Uninstall.
3250 *
3251 * Called on a worker thread via doUninstallThreadProc.
3252 *
3253 * @returns COM status code.
3254 * @param a_pstrName The name of the extension pack to uninstall.
3255 * @param a_fForcedRemoval Whether to be skip and ignore certain bits of
3256 * the extpack feedback. To deal with misbehaving
3257 * extension pack hooks.
3258 * @param a_pstrDisplayInfo Host specific display information hacks.
3259 */
3260HRESULT ExtPackManager::i_doUninstall(Utf8Str const *a_pstrName, bool a_fForcedRemoval, Utf8Str const *a_pstrDisplayInfo)
3261{
3262 Assert(m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON);
3263
3264 AutoCaller autoCaller(this);
3265 HRESULT hrc = autoCaller.hrc();
3266 if (SUCCEEDED(hrc))
3267 {
3268 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3269
3270 /*
3271 * Refresh the data we have on the extension pack as it
3272 * may be made stale by direct meddling or some other user.
3273 */
3274 ExtPack *pExtPack;
3275 hrc = i_refreshExtPack(a_pstrName->c_str(), false /*a_fUnusableIsError*/, &pExtPack);
3276 if (SUCCEEDED(hrc) && pExtPack)
3277 {
3278 /* We must leave the lock when calling i_areThereAnyRunningVMs,
3279 which means we have to redo the refresh call afterwards. */
3280 autoLock.release();
3281 bool fRunningVMs = i_areThereAnyRunningVMs();
3282 bool fVetoingCP = pExtPack->i_areThereCloudProviderUninstallVetos();
3283 bool fUnloadedCryptoMod = m->pVirtualBox->i_unloadCryptoIfModule() == S_OK;
3284 autoLock.acquire();
3285 if (a_fForcedRemoval || (!fRunningVMs && !fVetoingCP && fUnloadedCryptoMod))
3286 {
3287 hrc = i_refreshExtPack(a_pstrName->c_str(), false /*a_fUnusableIsError*/, &pExtPack);
3288 if (SUCCEEDED(hrc))
3289 {
3290 if (!pExtPack)
3291 {
3292 LogRel(("ExtPackManager: Extension pack '%s' is not installed, so nothing to uninstall.\n", a_pstrName->c_str()));
3293 hrc = S_OK; /* nothing to uninstall */
3294 }
3295 else
3296 {
3297 /*
3298 * Call the uninstall hook and unload the main dll.
3299 */
3300 hrc = pExtPack->i_callUninstallHookAndClose(m->pVirtualBox, a_fForcedRemoval);
3301 if (SUCCEEDED(hrc))
3302 {
3303 /*
3304 * Run the set-uid-to-root binary that performs the
3305 * uninstallation. Then refresh the object.
3306 *
3307 * This refresh is theorically subject to races, but it's of
3308 * the don't-do-that variety.
3309 */
3310 const char *pszForcedOpt = a_fForcedRemoval ? "--forced" : NULL;
3311 hrc = i_runSetUidToRootHelper(a_pstrDisplayInfo,
3312 "uninstall",
3313 "--base-dir", m->strBaseDir.c_str(),
3314 "--name", a_pstrName->c_str(),
3315 pszForcedOpt, /* Last as it may be NULL. */
3316 (const char *)NULL);
3317 if (SUCCEEDED(hrc))
3318 {
3319 hrc = i_refreshExtPack(a_pstrName->c_str(), false /*a_fUnusableIsError*/, &pExtPack);
3320 if (SUCCEEDED(hrc))
3321 {
3322 if (!pExtPack)
3323 {
3324 LogRel(("ExtPackManager: Successfully uninstalled extension pack '%s'.\n", a_pstrName->c_str()));
3325 m->pVirtualBox->i_onExtPackInstalled(*a_pstrName);
3326 }
3327 else
3328 hrc = setError(E_FAIL,
3329 tr("Uninstall extension pack '%s' failed under mysterious circumstances"),
3330 a_pstrName->c_str());
3331 }
3332 }
3333 else
3334 {
3335 ErrorInfoKeeper Eik;
3336 i_refreshExtPack(a_pstrName->c_str(), false /*a_fUnusableIsError*/, NULL);
3337 }
3338 }
3339 }
3340 }
3341 }
3342 else
3343 {
3344 if (fRunningVMs)
3345 {
3346 LogRel(("Uninstall extension pack '%s' failed because at least one VM is still running.", a_pstrName->c_str()));
3347 hrc = setError(E_FAIL, tr("Uninstall extension pack '%s' failed because at least one VM is still running"),
3348 a_pstrName->c_str());
3349 }
3350 else if (fVetoingCP)
3351 {
3352 LogRel(("Uninstall extension pack '%s' failed because at least one Cloud Provider is still busy.", a_pstrName->c_str()));
3353 hrc = setError(E_FAIL, tr("Uninstall extension pack '%s' failed because at least one Cloud Provider is still busy"),
3354 a_pstrName->c_str());
3355 }
3356 else if (!fUnloadedCryptoMod)
3357 {
3358 LogRel(("Uninstall extension pack '%s' failed because the cryptographic support module is still in use.", a_pstrName->c_str()));
3359 hrc = setError(E_FAIL, tr("Uninstall extension pack '%s' failed because the cryptographic support module is still in use"),
3360 a_pstrName->c_str());
3361 }
3362 else
3363 {
3364 LogRel(("Uninstall extension pack '%s' failed for an unknown reason.", a_pstrName->c_str()));
3365 hrc = setError(E_FAIL, tr("Uninstall extension pack '%s' failed for an unknown reason"),
3366 a_pstrName->c_str());
3367
3368 }
3369 }
3370 }
3371 else if (SUCCEEDED(hrc) && !pExtPack)
3372 {
3373 hrc = setError(E_FAIL, tr("Extension pack '%s' is not installed.\n"), a_pstrName->c_str());
3374 }
3375
3376 /*
3377 * Do VirtualBoxReady callbacks now for any freshly installed
3378 * extension pack (old ones will not be called).
3379 */
3380 if (m->enmContext == VBOXEXTPACKCTX_PER_USER_DAEMON)
3381 {
3382 autoLock.release();
3383 i_callAllVirtualBoxReadyHooks();
3384 }
3385 }
3386
3387 return hrc;
3388}
3389
3390
3391/**
3392 * Calls the pfnVirtualBoxReady hook for all working extension packs.
3393 *
3394 * @remarks The caller must not hold any locks.
3395 */
3396void ExtPackManager::i_callAllVirtualBoxReadyHooks(void)
3397{
3398 AutoCaller autoCaller(this);
3399 HRESULT hrc = autoCaller.hrc();
3400 if (FAILED(hrc))
3401 return;
3402 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3403 ComPtr<ExtPackManager> ptrSelfRef = this;
3404
3405 for (ExtPackList::iterator it = m->llInstalledExtPacks.begin();
3406 it != m->llInstalledExtPacks.end();
3407 /* advancing below */)
3408 {
3409 if ((*it)->i_callVirtualBoxReadyHook(m->pVirtualBox, &autoLock))
3410 it = m->llInstalledExtPacks.begin();
3411 else
3412 ++it;
3413 }
3414}
3415
3416
3417/**
3418 * Queries objects of type @a aObjUuid from all the extension packs.
3419 *
3420 * @returns COM status code.
3421 * @param aObjUuid The UUID of the kind of objects we're querying.
3422 * @param aObjects Where to return the objects.
3423 * @param a_pstrExtPackNames Where to return the corresponding extpack names (may be NULL).
3424 *
3425 * @remarks The caller must not hold any locks.
3426 */
3427HRESULT ExtPackManager::i_queryObjects(const com::Utf8Str &aObjUuid, std::vector<ComPtr<IUnknown> > &aObjects, std::vector<com::Utf8Str> *a_pstrExtPackNames)
3428{
3429 aObjects.clear();
3430 if (a_pstrExtPackNames)
3431 a_pstrExtPackNames->clear();
3432
3433 AutoCaller autoCaller(this);
3434 HRESULT hrc = autoCaller.hrc();
3435 if (SUCCEEDED(hrc))
3436 {
3437 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3438 ComPtr<ExtPackManager> ptrSelfRef = this;
3439
3440 for (ExtPackList::iterator it = m->llInstalledExtPacks.begin();
3441 it != m->llInstalledExtPacks.end();
3442 ++it)
3443 {
3444 ComPtr<IUnknown> ptrIf;
3445 HRESULT hrc2 = (*it)->queryObject(aObjUuid, ptrIf);
3446 if (SUCCEEDED(hrc2))
3447 {
3448 aObjects.push_back(ptrIf);
3449 if (a_pstrExtPackNames)
3450 a_pstrExtPackNames->push_back((*it)->m->Desc.strName);
3451 }
3452 else if (hrc2 != E_NOINTERFACE)
3453 hrc = hrc2;
3454 }
3455
3456 if (aObjects.size() > 0)
3457 hrc = S_OK;
3458 }
3459 return hrc;
3460}
3461
3462#endif /* !VBOX_COM_INPROC */
3463
3464#ifdef VBOX_COM_INPROC
3465/**
3466 * Calls the pfnConsoleReady hook for all working extension packs.
3467 *
3468 * @param a_pConsole The console interface.
3469 * @remarks The caller must not hold any locks.
3470 */
3471void ExtPackManager::i_callAllConsoleReadyHooks(IConsole *a_pConsole)
3472{
3473 AutoCaller autoCaller(this);
3474 HRESULT hrc = autoCaller.hrc();
3475 if (FAILED(hrc))
3476 return;
3477 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3478 ComPtr<ExtPackManager> ptrSelfRef = this;
3479
3480 for (ExtPackList::iterator it = m->llInstalledExtPacks.begin();
3481 it != m->llInstalledExtPacks.end();
3482 /* advancing below */)
3483 {
3484 if ((*it)->i_callConsoleReadyHook(a_pConsole, &autoLock))
3485 it = m->llInstalledExtPacks.begin();
3486 else
3487 ++it;
3488 }
3489}
3490#endif
3491
3492#ifndef VBOX_COM_INPROC
3493/**
3494 * Calls the pfnVMCreated hook for all working extension packs.
3495 *
3496 * @param a_pMachine The machine interface of the new VM.
3497 */
3498void ExtPackManager::i_callAllVmCreatedHooks(IMachine *a_pMachine)
3499{
3500 AutoCaller autoCaller(this);
3501 HRESULT hrc = autoCaller.hrc();
3502 if (FAILED(hrc))
3503 return;
3504 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3505 ComPtr<ExtPackManager> ptrSelfRef = this; /* paranoia */
3506 ExtPackList llExtPacks = m->llInstalledExtPacks;
3507
3508 for (ExtPackList::iterator it = llExtPacks.begin(); it != llExtPacks.end(); ++it)
3509 (*it)->i_callVmCreatedHook(m->pVirtualBox, a_pMachine, &autoLock);
3510}
3511#endif
3512
3513#ifdef VBOX_COM_INPROC
3514
3515/**
3516 * Calls the pfnVMConfigureVMM hook for all working extension packs.
3517 *
3518 * @returns VBox status code. Stops on the first failure, expecting the caller
3519 * to signal this to the caller of the CFGM constructor.
3520 * @param a_pConsole The console interface for the VM.
3521 * @param a_pVM The VM handle.
3522 * @param a_pVMM The VMM function table.
3523 */
3524int ExtPackManager::i_callAllVmConfigureVmmHooks(IConsole *a_pConsole, PVM a_pVM, PCVMMR3VTABLE a_pVMM)
3525{
3526 AutoCaller autoCaller(this);
3527 HRESULT hrc = autoCaller.hrc();
3528 if (FAILED(hrc))
3529 return Global::vboxStatusCodeFromCOM(hrc);
3530 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3531 ComPtr<ExtPackManager> ptrSelfRef = this; /* paranoia */
3532 ExtPackList llExtPacks = m->llInstalledExtPacks;
3533
3534 for (ExtPackList::iterator it = llExtPacks.begin(); it != llExtPacks.end(); ++it)
3535 {
3536 int vrc;
3537 (*it)->i_callVmConfigureVmmHook(a_pConsole, a_pVM, a_pVMM, &autoLock, &vrc);
3538 if (RT_FAILURE(vrc))
3539 return vrc;
3540 }
3541
3542 return VINF_SUCCESS;
3543}
3544
3545/**
3546 * Calls the pfnVMPowerOn hook for all working extension packs.
3547 *
3548 * @returns VBox status code. Stops on the first failure, expecting the caller
3549 * to not power on the VM.
3550 * @param a_pConsole The console interface for the VM.
3551 * @param a_pVM The VM handle.
3552 * @param a_pVMM The VMM function table.
3553 */
3554int ExtPackManager::i_callAllVmPowerOnHooks(IConsole *a_pConsole, PVM a_pVM, PCVMMR3VTABLE a_pVMM)
3555{
3556 AutoCaller autoCaller(this);
3557 HRESULT hrc = autoCaller.hrc();
3558 if (FAILED(hrc))
3559 return Global::vboxStatusCodeFromCOM(hrc);
3560 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3561 ComPtr<ExtPackManager> ptrSelfRef = this; /* paranoia */
3562 ExtPackList llExtPacks = m->llInstalledExtPacks;
3563
3564 for (ExtPackList::iterator it = llExtPacks.begin(); it != llExtPacks.end(); ++it)
3565 {
3566 int vrc;
3567 (*it)->i_callVmPowerOnHook(a_pConsole, a_pVM, a_pVMM, &autoLock, &vrc);
3568 if (RT_FAILURE(vrc))
3569 return vrc;
3570 }
3571
3572 return VINF_SUCCESS;
3573}
3574
3575/**
3576 * Calls the pfnVMPowerOff hook for all working extension packs.
3577 *
3578 * @param a_pConsole The console interface for the VM.
3579 * @param a_pVM The VM handle. Can be NULL.
3580 * @param a_pVMM The VMM function table.
3581 */
3582void ExtPackManager::i_callAllVmPowerOffHooks(IConsole *a_pConsole, PVM a_pVM, PCVMMR3VTABLE a_pVMM)
3583{
3584 AutoCaller autoCaller(this);
3585 HRESULT hrc = autoCaller.hrc();
3586 if (FAILED(hrc))
3587 return;
3588 AutoWriteLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3589 ComPtr<ExtPackManager> ptrSelfRef = this; /* paranoia */
3590 ExtPackList llExtPacks = m->llInstalledExtPacks;
3591
3592 for (ExtPackList::iterator it = llExtPacks.begin(); it != llExtPacks.end(); ++it)
3593 (*it)->i_callVmPowerOffHook(a_pConsole, a_pVM, a_pVMM, &autoLock);
3594}
3595
3596#endif /* VBOX_COM_INPROC */
3597
3598/**
3599 * Checks that the specified extension pack contains a VRDE module and that it
3600 * is shipshape.
3601 *
3602 * @returns S_OK if ok, appropriate failure status code with details.
3603 * @param a_pstrExtPack The name of the extension pack.
3604 */
3605HRESULT ExtPackManager::i_checkVrdeExtPack(Utf8Str const *a_pstrExtPack)
3606{
3607 AutoCaller autoCaller(this);
3608 HRESULT hrc = autoCaller.hrc();
3609 if (SUCCEEDED(hrc))
3610 {
3611 AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3612
3613 ExtPack *pExtPack = i_findExtPack(a_pstrExtPack->c_str());
3614 if (pExtPack)
3615 hrc = pExtPack->i_checkVrde();
3616 else
3617 hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No extension pack by the name '%s' was found"), a_pstrExtPack->c_str());
3618 }
3619
3620 return hrc;
3621}
3622
3623/**
3624 * Gets the full path to the VRDE library of the specified extension pack.
3625 *
3626 * This will do extacly the same as checkVrdeExtPack and then resolve the
3627 * library path.
3628 *
3629 * @returns VINF_SUCCESS if a path is returned, VBox error status and message
3630 * return if not.
3631 * @param a_pstrExtPack The extension pack.
3632 * @param a_pstrVrdeLibrary Where to return the path.
3633 */
3634int ExtPackManager::i_getVrdeLibraryPathForExtPack(Utf8Str const *a_pstrExtPack, Utf8Str *a_pstrVrdeLibrary)
3635{
3636 AutoCaller autoCaller(this);
3637 HRESULT hrc = autoCaller.hrc();
3638 if (SUCCEEDED(hrc))
3639 {
3640 AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3641
3642 ExtPack *pExtPack = i_findExtPack(a_pstrExtPack->c_str());
3643 if (pExtPack)
3644 hrc = pExtPack->i_getVrdpLibraryName(a_pstrVrdeLibrary);
3645 else
3646 hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No extension pack by the name '%s' was found"),
3647 a_pstrExtPack->c_str());
3648 }
3649
3650 return Global::vboxStatusCodeFromCOM(hrc);
3651}
3652
3653/**
3654 * Checks that the specified extension pack contains a cryptographic module and that it
3655 * is shipshape.
3656 *
3657 * @returns S_OK if ok, appropriate failure status code with details.
3658 * @param a_pstrExtPack The name of the extension pack.
3659 */
3660HRESULT ExtPackManager::i_checkCryptoExtPack(Utf8Str const *a_pstrExtPack)
3661{
3662 AutoCaller autoCaller(this);
3663 HRESULT hrc = autoCaller.hrc();
3664 if (SUCCEEDED(hrc))
3665 {
3666 AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3667
3668 ExtPack *pExtPack = i_findExtPack(a_pstrExtPack->c_str());
3669 if (pExtPack)
3670 hrc = pExtPack->i_checkCrypto();
3671 else
3672 hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No extension pack by the name '%s' was found"), a_pstrExtPack->c_str());
3673 }
3674
3675 return hrc;
3676}
3677
3678/**
3679 * Gets the full path to the cryptographic library of the specified extension pack.
3680 *
3681 * This will do extacly the same as checkCryptoExtPack and then resolve the
3682 * library path.
3683 *
3684 * @returns VINF_SUCCESS if a path is returned, VBox error status and message
3685 * return if not.
3686 * @param a_pstrExtPack The extension pack.
3687 * @param a_pstrCryptoLibrary Where to return the path.
3688 */
3689int ExtPackManager::i_getCryptoLibraryPathForExtPack(Utf8Str const *a_pstrExtPack, Utf8Str *a_pstrCryptoLibrary)
3690{
3691 AutoCaller autoCaller(this);
3692 HRESULT hrc = autoCaller.hrc();
3693 if (SUCCEEDED(hrc))
3694 {
3695 AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3696
3697 ExtPack *pExtPack = i_findExtPack(a_pstrExtPack->c_str());
3698 if (pExtPack)
3699 hrc = pExtPack->i_getCryptoLibraryName(a_pstrCryptoLibrary);
3700 else
3701 hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No extension pack by the name '%s' was found"),
3702 a_pstrExtPack->c_str());
3703 }
3704
3705 return Global::vboxStatusCodeFromCOM(hrc);
3706}
3707
3708
3709/**
3710 * Gets the full path to the specified library of the specified extension pack.
3711 *
3712 * @returns S_OK if a path is returned, COM error status and message return if
3713 * not.
3714 * @param a_pszModuleName The library.
3715 * @param a_pszExtPack The extension pack.
3716 * @param a_pstrLibrary Where to return the path.
3717 */
3718HRESULT ExtPackManager::i_getLibraryPathForExtPack(const char *a_pszModuleName, const char *a_pszExtPack, Utf8Str *a_pstrLibrary)
3719{
3720 AutoCaller autoCaller(this);
3721 HRESULT hrc = autoCaller.hrc();
3722 if (SUCCEEDED(hrc))
3723 {
3724 AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3725
3726 ExtPack *pExtPack = i_findExtPack(a_pszExtPack);
3727 if (pExtPack)
3728 hrc = pExtPack->i_getLibraryName(a_pszModuleName, a_pstrLibrary);
3729 else
3730 hrc = setError(VBOX_E_OBJECT_NOT_FOUND, tr("No extension pack by the name '%s' was found"), a_pszExtPack);
3731 }
3732
3733 return hrc;
3734}
3735
3736/**
3737 * Gets the name of the default VRDE extension pack.
3738 *
3739 * @returns S_OK or some COM error status on red tape failure.
3740 * @param a_pstrExtPack Where to return the extension pack name. Returns
3741 * empty if no extension pack wishes to be the default
3742 * VRDP provider.
3743 */
3744HRESULT ExtPackManager::i_getDefaultVrdeExtPack(Utf8Str *a_pstrExtPack)
3745{
3746 a_pstrExtPack->setNull();
3747
3748 AutoCaller autoCaller(this);
3749 HRESULT hrc = autoCaller.hrc();
3750 if (SUCCEEDED(hrc))
3751 {
3752 AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3753
3754 for (ExtPackList::iterator it = m->llInstalledExtPacks.begin();
3755 it != m->llInstalledExtPacks.end();
3756 ++it)
3757 {
3758 if ((*it)->i_wantsToBeDefaultVrde())
3759 {
3760 *a_pstrExtPack = (*it)->m->Desc.strName;
3761 break;
3762 }
3763 }
3764 }
3765 return hrc;
3766}
3767
3768/**
3769 * Gets the name of the default cryptographic extension pack.
3770 *
3771 * @returns S_OK or some COM error status on red tape failure.
3772 * @param a_pstrExtPack Where to return the extension pack name. Returns
3773 * empty if no extension pack wishes to be the default
3774 * VRDP provider.
3775 */
3776HRESULT ExtPackManager::i_getDefaultCryptoExtPack(Utf8Str *a_pstrExtPack)
3777{
3778 a_pstrExtPack->setNull();
3779
3780 AutoCaller autoCaller(this);
3781 HRESULT hrc = autoCaller.hrc();
3782 if (SUCCEEDED(hrc))
3783 {
3784 AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3785
3786 for (ExtPackList::iterator it = m->llInstalledExtPacks.begin();
3787 it != m->llInstalledExtPacks.end();
3788 ++it)
3789 {
3790 if ((*it)->i_wantsToBeDefaultCrypto())
3791 {
3792 *a_pstrExtPack = (*it)->m->Desc.strName;
3793 break;
3794 }
3795 }
3796 }
3797 return hrc;
3798}
3799
3800/**
3801 * Checks if an extension pack is (present and) usable.
3802 *
3803 * @returns @c true if it is, otherwise @c false.
3804 * @param a_pszExtPack The name of the extension pack.
3805 */
3806bool ExtPackManager::i_isExtPackUsable(const char *a_pszExtPack)
3807{
3808 AutoCaller autoCaller(this);
3809 HRESULT hrc = autoCaller.hrc();
3810 if (FAILED(hrc))
3811 return false;
3812 AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3813
3814 ExtPack *pExtPack = i_findExtPack(a_pszExtPack);
3815 return pExtPack != NULL
3816 && pExtPack->m->fUsable;
3817}
3818
3819/**
3820 * Dumps all extension packs to the release log.
3821 */
3822void ExtPackManager::i_dumpAllToReleaseLog(void)
3823{
3824 AutoCaller autoCaller(this);
3825 HRESULT hrc = autoCaller.hrc();
3826 if (FAILED(hrc))
3827 return;
3828 AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3829
3830 LogRel(("Installed Extension Packs:\n"));
3831 for (ExtPackList::iterator it = m->llInstalledExtPacks.begin();
3832 it != m->llInstalledExtPacks.end();
3833 ++it)
3834 {
3835 ExtPack::Data *pExtPackData = (*it)->m;
3836 if (pExtPackData)
3837 {
3838 if (pExtPackData->fUsable)
3839 LogRel((" %s (Version: %s r%u%s%s; VRDE Module: %s; Crypto Module: %s)\n",
3840 pExtPackData->Desc.strName.c_str(),
3841 pExtPackData->Desc.strVersion.c_str(),
3842 pExtPackData->Desc.uRevision,
3843 pExtPackData->Desc.strEdition.isEmpty() ? "" : " ",
3844 pExtPackData->Desc.strEdition.c_str(),
3845 pExtPackData->Desc.strVrdeModule.c_str(),
3846 pExtPackData->Desc.strCryptoModule.c_str() ));
3847 else
3848 LogRel((" %s (Version: %s r%u%s%s; VRDE Module: %s; Crypto Module: %s unusable because of '%s')\n",
3849 pExtPackData->Desc.strName.c_str(),
3850 pExtPackData->Desc.strVersion.c_str(),
3851 pExtPackData->Desc.uRevision,
3852 pExtPackData->Desc.strEdition.isEmpty() ? "" : " ",
3853 pExtPackData->Desc.strEdition.c_str(),
3854 pExtPackData->Desc.strVrdeModule.c_str(),
3855 pExtPackData->Desc.strCryptoModule.c_str(),
3856 pExtPackData->strWhyUnusable.c_str() ));
3857 }
3858 else
3859 LogRel((" pExtPackData is NULL\n"));
3860 }
3861
3862 if (!m->llInstalledExtPacks.size())
3863 LogRel((" None installed!\n"));
3864}
3865
3866/**
3867 * Gets the update counter (reflecting extpack list updates).
3868 */
3869uint64_t ExtPackManager::i_getUpdateCounter(void)
3870{
3871 AutoCaller autoCaller(this);
3872 HRESULT hrc = autoCaller.hrc();
3873 if (FAILED(hrc))
3874 return 0;
3875 AutoReadLock autoLock(this COMMA_LOCKVAL_SRC_POS);
3876 return m->cUpdate;
3877}
3878
3879/* vi: set tabstop=4 shiftwidth=4 expandtab: */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette