VirtualBox

source: vbox/trunk/src/VBox/Main/ExtPackUtil.cpp@ 35061

Last change on this file since 35061 was 34967, checked in by vboxsync, 14 years ago

Moved and extended RTVfsIoStrmValidateUtf8Encoding.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 42.9 KB
Line 
1/* $Id: ExtPackUtil.cpp 34967 2010-12-10 17:52:01Z vboxsync $ */
2/** @file
3 * VirtualBox Main - Extension Pack Utilities and definitions, VBoxC, VBoxSVC, ++.
4 */
5
6/*
7 * Copyright (C) 2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19/*******************************************************************************
20* Header Files *
21*******************************************************************************/
22#include "include/ExtPackUtil.h"
23
24#include <iprt/ctype.h>
25#include <iprt/dir.h>
26#include <iprt/file.h>
27#include <iprt/manifest.h>
28#include <iprt/param.h>
29#include <iprt/path.h>
30#include <iprt/string.h>
31#include <iprt/vfs.h>
32#include <iprt/tar.h>
33#include <iprt/zip.h>
34#include <iprt/cpp/xml.h>
35
36#include <VBox/log.h>
37
38
39/**
40 * Worker for VBoxExtPackLoadDesc that loads the plug-in descriptors.
41 *
42 * @returns Same as VBoxExtPackLoadDesc.
43 * @param pVBoxExtPackElm
44 * @param pcPlugIns Where to return the number of plug-ins in the
45 * array.
46 * @param paPlugIns Where to return the plug-in descriptor array.
47 * (RTMemFree it even on failure)
48 */
49static iprt::MiniString *
50vboxExtPackLoadPlugInDescs(const xml::ElementNode *pVBoxExtPackElm,
51 uint32_t *pcPlugIns, PVBOXEXTPACKPLUGINDESC *paPlugIns)
52{
53 *pcPlugIns = 0;
54 *paPlugIns = NULL;
55
56 /** @todo plug-ins */
57 NOREF(pVBoxExtPackElm);
58
59 return NULL;
60}
61
62/**
63 * Clears the extension pack descriptor.
64 *
65 * @param a_pExtPackDesc The descriptor to clear.
66 */
67static void vboxExtPackClearDesc(PVBOXEXTPACKDESC a_pExtPackDesc)
68{
69 a_pExtPackDesc->strName.setNull();
70 a_pExtPackDesc->strDescription.setNull();
71 a_pExtPackDesc->strVersion.setNull();
72 a_pExtPackDesc->uRevision = 0;
73 a_pExtPackDesc->strMainModule.setNull();
74 a_pExtPackDesc->strVrdeModule.setNull();
75 a_pExtPackDesc->cPlugIns = 0;
76 a_pExtPackDesc->paPlugIns = NULL;
77 a_pExtPackDesc->fShowLicense = false;
78}
79
80/**
81 * Load the extension pack descriptor from an XML document.
82 *
83 * @returns NULL on success, pointer to an error message on failure (caller
84 * deletes it).
85 * @param a_pDoc Pointer to the the XML document.
86 * @param a_pExtPackDesc Where to store the extension pack descriptor.
87 */
88static iprt::MiniString *vboxExtPackLoadDescFromDoc(xml::Document *a_pDoc, PVBOXEXTPACKDESC a_pExtPackDesc)
89{
90 /*
91 * Get the main element and check its version.
92 */
93 const xml::ElementNode *pVBoxExtPackElm = a_pDoc->getRootElement();
94 if ( !pVBoxExtPackElm
95 || strcmp(pVBoxExtPackElm->getName(), "VirtualBoxExtensionPack") != 0)
96 return new iprt::MiniString("No VirtualBoxExtensionPack element");
97
98 iprt::MiniString strFormatVersion;
99 if (!pVBoxExtPackElm->getAttributeValue("version", strFormatVersion))
100 return new iprt::MiniString("Missing format version");
101 if (!strFormatVersion.equals("1.0"))
102 return &(new iprt::MiniString("Unsupported format version: "))->append(strFormatVersion);
103
104 /*
105 * Read and validate mandatory bits.
106 */
107 const xml::ElementNode *pNameElm = pVBoxExtPackElm->findChildElement("Name");
108 if (!pNameElm)
109 return new iprt::MiniString("The 'Name' element is missing");
110 const char *pszName = pNameElm->getValue();
111 if (!VBoxExtPackIsValidName(pszName))
112 return &(new iprt::MiniString("Invalid name: "))->append(pszName);
113
114 const xml::ElementNode *pDescElm = pVBoxExtPackElm->findChildElement("Description");
115 if (!pDescElm)
116 return new iprt::MiniString("The 'Description' element is missing");
117 const char *pszDesc = pDescElm->getValue();
118 if (!pszDesc || *pszDesc == '\0')
119 return new iprt::MiniString("The 'Description' element is empty");
120 if (strpbrk(pszDesc, "\n\r\t\v\b") != NULL)
121 return new iprt::MiniString("The 'Description' must not contain control characters");
122
123 const xml::ElementNode *pVersionElm = pVBoxExtPackElm->findChildElement("Version");
124 if (!pVersionElm)
125 return new iprt::MiniString("The 'Version' element is missing");
126 const char *pszVersion = pVersionElm->getValue();
127 if (!pszVersion || *pszVersion == '\0')
128 return new iprt::MiniString("The 'Version' element is empty");
129 if (!VBoxExtPackIsValidVersionString(pszVersion))
130 return &(new iprt::MiniString("Invalid version string: "))->append(pszVersion);
131
132 uint32_t uRevision;
133 if (!pVersionElm->getAttributeValue("revision", uRevision))
134 uRevision = 0;
135
136 const xml::ElementNode *pMainModuleElm = pVBoxExtPackElm->findChildElement("MainModule");
137 if (!pMainModuleElm)
138 return new iprt::MiniString("The 'MainModule' element is missing");
139 const char *pszMainModule = pMainModuleElm->getValue();
140 if (!pszMainModule || *pszMainModule == '\0')
141 return new iprt::MiniString("The 'MainModule' element is empty");
142 if (!VBoxExtPackIsValidModuleString(pszMainModule))
143 return &(new iprt::MiniString("Invalid main module string: "))->append(pszMainModule);
144
145 /*
146 * The VRDE module, optional.
147 * Accept both none and empty as tokens of no VRDE module.
148 */
149 const char *pszVrdeModule = NULL;
150 const xml::ElementNode *pVrdeModuleElm = pVBoxExtPackElm->findChildElement("VRDEModule");
151 if (pVrdeModuleElm)
152 {
153 pszVrdeModule = pVrdeModuleElm->getValue();
154 if (!pszVrdeModule || *pszVrdeModule == '\0')
155 pszVrdeModule = NULL;
156 else if (!VBoxExtPackIsValidModuleString(pszVrdeModule))
157 return &(new iprt::MiniString("Invalid VRDE module string: "))->append(pszVrdeModule);
158 }
159
160 /*
161 * Whether to show the license, optional. (presense is enough here)
162 */
163 const xml::ElementNode *pShowLicenseElm = pVBoxExtPackElm->findChildElement("ShowLicense");
164 bool fShowLicense = pShowLicenseElm != NULL;
165
166 /*
167 * Parse plug-in descriptions (last because of the manual memory management).
168 */
169 uint32_t cPlugIns = 0;
170 PVBOXEXTPACKPLUGINDESC paPlugIns = NULL;
171 iprt::MiniString *pstrRet = vboxExtPackLoadPlugInDescs(pVBoxExtPackElm, &cPlugIns, &paPlugIns);
172 if (pstrRet)
173 {
174 RTMemFree(paPlugIns);
175 return pstrRet;
176 }
177
178 /*
179 * Everything seems fine, fill in the return values and return successfully.
180 */
181 a_pExtPackDesc->strName = pszName;
182 a_pExtPackDesc->strDescription = pszDesc;
183 a_pExtPackDesc->strVersion = pszVersion;
184 a_pExtPackDesc->uRevision = uRevision;
185 a_pExtPackDesc->strMainModule = pszMainModule;
186 a_pExtPackDesc->strVrdeModule = pszVrdeModule;
187 a_pExtPackDesc->cPlugIns = cPlugIns;
188 a_pExtPackDesc->paPlugIns = paPlugIns;
189 a_pExtPackDesc->fShowLicense = fShowLicense;
190
191 return NULL;
192}
193
194/**
195 * Reads the extension pack descriptor.
196 *
197 * @returns NULL on success, pointer to an error message on failure (caller
198 * deletes it).
199 * @param a_pszDir The directory containing the description file.
200 * @param a_pExtPackDesc Where to store the extension pack descriptor.
201 * @param a_pObjInfo Where to store the object info for the file (unix
202 * attribs). Optional.
203 */
204iprt::MiniString *VBoxExtPackLoadDesc(const char *a_pszDir, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo)
205{
206 vboxExtPackClearDesc(a_pExtPackDesc);
207
208 /*
209 * Validate, open and parse the XML file.
210 */
211 char szFilePath[RTPATH_MAX];
212 int vrc = RTPathJoin(szFilePath, sizeof(szFilePath), a_pszDir, VBOX_EXTPACK_DESCRIPTION_NAME);
213 if (RT_FAILURE(vrc))
214 return new iprt::MiniString("RTPathJoin failed with %Rrc", vrc);
215
216 RTFSOBJINFO ObjInfo;
217 vrc = RTPathQueryInfoEx(szFilePath, &ObjInfo, RTFSOBJATTRADD_UNIX, RTPATH_F_ON_LINK);
218 if (RT_FAILURE(vrc))
219 return &(new iprt::MiniString())->printf("RTPathQueryInfoEx failed with %Rrc", vrc);
220 if (a_pObjInfo)
221 *a_pObjInfo = ObjInfo;
222 if (!RTFS_IS_FILE(ObjInfo.Attr.fMode))
223 {
224 if (RTFS_IS_SYMLINK(ObjInfo.Attr.fMode))
225 return new iprt::MiniString("The XML file is symlinked, that is not allowed");
226 return &(new iprt::MiniString)->printf("The XML file is not a file (fMode=%#x)", ObjInfo.Attr.fMode);
227 }
228
229 xml::Document Doc;
230 {
231 xml::XmlFileParser Parser;
232 try
233 {
234 Parser.read(szFilePath, Doc);
235 }
236 catch (xml::XmlError Err)
237 {
238 return new iprt::MiniString(Err.what());
239 }
240 }
241
242 /*
243 * Hand the xml doc over to the common code.
244 */
245 return vboxExtPackLoadDescFromDoc(&Doc, a_pExtPackDesc);
246}
247
248/**
249 * Reads the extension pack descriptor.
250 *
251 * @returns NULL on success, pointer to an error message on failure (caller
252 * deletes it).
253 * @param a_pszDir The directory containing the description file.
254 * @param a_pExtPackDesc Where to store the extension pack descriptor.
255 * @param a_pObjInfo Where to store the object info for the file (unix
256 * attribs). Optional.
257 */
258iprt::MiniString *VBoxExtPackLoadDescFromVfsFile(RTVFSFILE hVfsFile, PVBOXEXTPACKDESC a_pExtPackDesc, PRTFSOBJINFO a_pObjInfo)
259{
260 vboxExtPackClearDesc(a_pExtPackDesc);
261
262 /*
263 * Query the object info.
264 */
265 RTFSOBJINFO ObjInfo;
266 int rc = RTVfsFileQueryInfo(hVfsFile, &ObjInfo, RTFSOBJATTRADD_UNIX);
267 if (RT_FAILURE(rc))
268 return &(new iprt::MiniString)->printf("RTVfsFileQueryInfo failed: %Rrc", rc);
269 if (a_pObjInfo)
270 *a_pObjInfo = ObjInfo;
271
272 /*
273 * The simple approach, read the whole thing into memory and pass this to
274 * the XML parser.
275 */
276
277 /* Check the file size. */
278 if (ObjInfo.cbObject > _1M || ObjInfo.cbObject < 0)
279 return &(new iprt::MiniString)->printf("The XML file is too large (%'RU64 bytes)", ObjInfo.cbObject);
280 size_t const cbFile = (size_t)ObjInfo.cbObject;
281
282 /* Rewind to the start of the file. */
283 rc = RTVfsFileSeek(hVfsFile, 0, RTFILE_SEEK_BEGIN, NULL);
284 if (RT_FAILURE(rc))
285 return &(new iprt::MiniString)->printf("RTVfsFileSeek(,0,BEGIN) failed: %Rrc", rc);
286
287 /* Allocate memory and read the file content into it. */
288 void *pvFile = RTMemTmpAlloc(cbFile);
289 if (!pvFile)
290 return &(new iprt::MiniString)->printf("RTMemTmpAlloc(%zu) failed", cbFile);
291
292 iprt::MiniString *pstrErr = NULL;
293 rc = RTVfsFileRead(hVfsFile, pvFile, cbFile, NULL);
294 if (RT_FAILURE(rc))
295 pstrErr = &(new iprt::MiniString)->printf("RTVfsFileRead failed: %Rrc", rc);
296
297 /*
298 * Parse the file.
299 */
300 xml::Document Doc;
301 if (RT_SUCCESS(rc))
302 {
303 xml::XmlMemParser Parser;
304 iprt::MiniString strFileName = VBOX_EXTPACK_DESCRIPTION_NAME;
305 try
306 {
307 Parser.read(pvFile, cbFile, strFileName, Doc);
308 }
309 catch (xml::XmlError Err)
310 {
311 pstrErr = new iprt::MiniString(Err.what());
312 rc = VERR_PARSE_ERROR;
313 }
314 }
315 RTMemTmpFree(pvFile);
316
317 /*
318 * Hand the xml doc over to the common code.
319 */
320 if (RT_SUCCESS(rc))
321 pstrErr = vboxExtPackLoadDescFromDoc(&Doc, a_pExtPackDesc);
322
323 return pstrErr;
324}
325
326/**
327 * Frees all resources associated with a extension pack descriptor.
328 *
329 * @param a_pExtPackDesc The extension pack descriptor which members
330 * should be freed.
331 */
332void VBoxExtPackFreeDesc(PVBOXEXTPACKDESC a_pExtPackDesc)
333{
334 if (!a_pExtPackDesc)
335 return;
336
337 a_pExtPackDesc->strName.setNull();
338 a_pExtPackDesc->strDescription.setNull();
339 a_pExtPackDesc->strVersion.setNull();
340 a_pExtPackDesc->uRevision = 0;
341 a_pExtPackDesc->strMainModule.setNull();
342 a_pExtPackDesc->strVrdeModule.setNull();
343 a_pExtPackDesc->cPlugIns = 0;
344 RTMemFree(a_pExtPackDesc->paPlugIns);
345 a_pExtPackDesc->paPlugIns = NULL;
346 a_pExtPackDesc->fShowLicense = false;
347}
348
349/**
350 * Extract the extension pack name from the tarball path.
351 *
352 * @returns String containing the name on success, the caller must delete it.
353 * NULL if no valid name was found or if we ran out of memory.
354 * @param pszTarball The path to the tarball.
355 */
356iprt::MiniString *VBoxExtPackExtractNameFromTarballPath(const char *pszTarball)
357{
358 /*
359 * Skip ahead to the filename part and count the number of characters
360 * that matches the criteria for a mangled extension pack name.
361 */
362 const char *pszSrc = RTPathFilename(pszTarball);
363 if (!pszSrc)
364 return NULL;
365
366 size_t off = 0;
367 while (RT_C_IS_ALNUM(pszSrc[off]) || pszSrc[off] == '_')
368 off++;
369
370 /*
371 * Check min and max name limits.
372 */
373 if ( off > VBOX_EXTPACK_NAME_MAX_LEN
374 || off < VBOX_EXTPACK_NAME_MIN_LEN)
375 return NULL;
376
377 /*
378 * Return the unmangled name.
379 */
380 return VBoxExtPackUnmangleName(pszSrc, off);
381}
382
383/**
384 * Validates the extension pack name.
385 *
386 * @returns true if valid, false if not.
387 * @param pszName The name to validate.
388 * @sa VBoxExtPackExtractNameFromTarballPath
389 */
390bool VBoxExtPackIsValidName(const char *pszName)
391{
392 if (!pszName)
393 return false;
394
395 /*
396 * Check the characters making up the name, only english alphabet
397 * characters, decimal digits and spaces are allowed.
398 */
399 size_t off = 0;
400 while (pszName[off])
401 {
402 if (!RT_C_IS_ALNUM(pszName[off]) && pszName[off] != ' ')
403 return false;
404 off++;
405 }
406
407 /*
408 * Check min and max name limits.
409 */
410 if ( off > VBOX_EXTPACK_NAME_MAX_LEN
411 || off < VBOX_EXTPACK_NAME_MIN_LEN)
412 return false;
413
414 return true;
415}
416
417/**
418 * Checks if an alledged manged extension pack name.
419 *
420 * @returns true if valid, false if not.
421 * @param pszMangledName The mangled name to validate.
422 * @param cchMax The max number of chars to test.
423 * @sa VBoxExtPackMangleName
424 */
425bool VBoxExtPackIsValidMangledName(const char *pszMangledName, size_t cchMax /*= RTSTR_MAX*/)
426{
427 if (!pszMangledName)
428 return false;
429
430 /*
431 * Check the characters making up the name, only english alphabet
432 * characters, decimal digits and underscores (=space) are allowed.
433 */
434 size_t off = 0;
435 while (off < cchMax && pszMangledName[off])
436 {
437 if (!RT_C_IS_ALNUM(pszMangledName[off]) && pszMangledName[off] != '_')
438 return false;
439 off++;
440 }
441
442 /*
443 * Check min and max name limits.
444 */
445 if ( off > VBOX_EXTPACK_NAME_MAX_LEN
446 || off < VBOX_EXTPACK_NAME_MIN_LEN)
447 return false;
448
449 return true;
450}
451
452/**
453 * Mangle an extension pack name so it can be used by a directory or file name.
454 *
455 * @returns String containing the mangled name on success, the caller must
456 * delete it. NULL on failure.
457 * @param pszName The unmangled name.
458 * @sa VBoxExtPackUnmangleName, VBoxExtPackIsValidMangledName
459 */
460iprt::MiniString *VBoxExtPackMangleName(const char *pszName)
461{
462 AssertReturn(VBoxExtPackIsValidName(pszName), NULL);
463
464 char szTmp[VBOX_EXTPACK_NAME_MAX_LEN + 1];
465 size_t off = 0;
466 char ch;
467 while ((ch = pszName[off]) != '\0')
468 {
469 if (ch == ' ')
470 ch = '_';
471 szTmp[off++] = ch;
472 }
473 szTmp[off] = '\0';
474 Assert(VBoxExtPackIsValidMangledName(szTmp));
475
476 return new iprt::MiniString(szTmp, off);
477}
478
479/**
480 * Unmangle an extension pack name (reverses VBoxExtPackMangleName).
481 *
482 * @returns String containing the mangled name on success, the caller must
483 * delete it. NULL on failure.
484 * @param pszMangledName The mangled name.
485 * @param cchMax The max name length. RTSTR_MAX is fine.
486 * @sa VBoxExtPackMangleName, VBoxExtPackIsValidMangledName
487 */
488iprt::MiniString *VBoxExtPackUnmangleName(const char *pszMangledName, size_t cchMax)
489{
490 AssertReturn(VBoxExtPackIsValidMangledName(pszMangledName, cchMax), NULL);
491
492 char szTmp[VBOX_EXTPACK_NAME_MAX_LEN + 1];
493 size_t off = 0;
494 char ch;
495 while ( off < cchMax
496 && (ch = pszMangledName[off]) != '\0')
497 {
498 if (ch == '_')
499 ch = ' ';
500 else
501 AssertReturn(RT_C_IS_ALNUM(ch) || ch == ' ', NULL);
502 szTmp[off++] = ch;
503 }
504 szTmp[off] = '\0';
505 AssertReturn(VBoxExtPackIsValidName(szTmp), NULL);
506
507 return new iprt::MiniString(szTmp, off);
508}
509
510/**
511 * Constructs the extension pack directory path.
512 *
513 * A combination of RTPathJoin and VBoxExtPackMangleName.
514 *
515 * @returns IPRT status code like RTPathJoin.
516 * @param pszExtPackDir Where to return the directory path.
517 * @param cbExtPackDir The size of the return buffer.
518 * @param pszParentDir The parent directory (".../Extensions").
519 * @param pszName The extension pack name, unmangled.
520 */
521int VBoxExtPackCalcDir(char *pszExtPackDir, size_t cbExtPackDir, const char *pszParentDir, const char *pszName)
522{
523 AssertReturn(VBoxExtPackIsValidName(pszName), VERR_INTERNAL_ERROR_5);
524
525 iprt::MiniString *pstrMangledName = VBoxExtPackMangleName(pszName);
526 if (!pstrMangledName)
527 return VERR_INTERNAL_ERROR_4;
528
529 int vrc = RTPathJoin(pszExtPackDir, cbExtPackDir, pszParentDir, pstrMangledName->c_str());
530 delete pstrMangledName;
531
532 return vrc;
533}
534
535
536/**
537 * Validates the extension pack version string.
538 *
539 * @returns true if valid, false if not.
540 * @param pszVersion The version string to validate.
541 */
542bool VBoxExtPackIsValidVersionString(const char *pszVersion)
543{
544 if (!pszVersion || *pszVersion == '\0')
545 return false;
546
547 /* 1.x.y.z... */
548 for (;;)
549 {
550 if (!RT_C_IS_DIGIT(*pszVersion))
551 return false;
552 do
553 pszVersion++;
554 while (RT_C_IS_DIGIT(*pszVersion));
555 if (*pszVersion != '.')
556 break;
557 pszVersion++;
558 }
559
560 /* upper case string + numbers indicating the build type */
561 if (*pszVersion == '-' || *pszVersion == '_')
562 {
563 do
564 pszVersion++;
565 while ( RT_C_IS_DIGIT(*pszVersion)
566 || RT_C_IS_UPPER(*pszVersion)
567 || *pszVersion == '-'
568 || *pszVersion == '_');
569 }
570
571 /* revision or nothing */
572 if (*pszVersion != '\0')
573 {
574 if (*pszVersion != 'r')
575 return false;
576 do
577 pszVersion++;
578 while (RT_C_IS_DIGIT(*pszVersion));
579 }
580
581 return *pszVersion == '\0';
582}
583
584/**
585 * Validates an extension pack module string.
586 *
587 * @returns true if valid, false if not.
588 * @param pszModule The module string to validate.
589 */
590bool VBoxExtPackIsValidModuleString(const char *pszModule)
591{
592 if (!pszModule || *pszModule == '\0')
593 return false;
594
595 /* Restricted charset, no extensions (dots). */
596 while ( RT_C_IS_ALNUM(*pszModule)
597 || *pszModule == '-'
598 || *pszModule == '_')
599 pszModule++;
600
601 return *pszModule == '\0';
602}
603
604/**
605 * RTStrPrintfv wrapper.
606 *
607 * @returns @a rc
608 * @param rc The status code to return.
609 * @param pszError The error buffer.
610 * @param cbError The size of the buffer.
611 * @param pszFormat The error message format string.
612 * @param ... Format arguments.
613 */
614static int vboxExtPackReturnError(int rc, char *pszError, size_t cbError, const char *pszFormat, ...)
615{
616 va_list va;
617 va_start(va, pszFormat);
618 RTStrPrintfV(pszError, cbError, pszFormat, va);
619 va_end(va);
620 return rc;
621}
622
623/**
624 * RTStrPrintfv wrapper.
625 *
626 * @param pszError The error buffer.
627 * @param cbError The size of the buffer.
628 * @param pszFormat The error message format string.
629 * @param ... Format arguments.
630 */
631static void vboxExtPackSetError(char *pszError, size_t cbError, const char *pszFormat, ...)
632{
633 va_list va;
634 va_start(va, pszFormat);
635 RTStrPrintfV(pszError, cbError, pszFormat, va);
636 va_end(va);
637}
638
639/**
640 * Verifies the manifest and its signature.
641 *
642 * @returns VBox status code, failures with message.
643 * @param hManifestFile The xml from the extension pack.
644 * @param pszExtPackName The expected extension pack name. This can be
645 * NULL, in which we don't have any expectations.
646 * @param pszError Where to store an error message on failure.
647 * @param cbError The size of the buffer @a pszError points to.
648 */
649static int vboxExtPackVerifyXml(RTVFSFILE hXmlFile, const char *pszExtPackName, char *pszError, size_t cbError)
650{
651 /*
652 * Load the XML.
653 */
654 VBOXEXTPACKDESC ExtPackDesc;
655 iprt::MiniString *pstrErr = VBoxExtPackLoadDescFromVfsFile(hXmlFile, &ExtPackDesc, NULL);
656 if (pstrErr)
657 {
658 RTStrCopy(pszError, cbError, pstrErr->c_str());
659 delete pstrErr;
660 return VERR_PARSE_ERROR;
661 }
662
663 /*
664 * Check the name.
665 */
666 /** @todo drop this restriction after the old install interface is
667 * dropped. */
668 int rc = VINF_SUCCESS;
669 if ( pszExtPackName
670 && !ExtPackDesc.strName.equalsIgnoreCase(pszExtPackName))
671 rc = vboxExtPackReturnError(VERR_NOT_EQUAL, pszError, cbError,
672 "The name of the downloaded file and the name stored inside the extension pack does not match"
673 " (xml='%s' file='%s')", ExtPackDesc.strName.c_str(), pszExtPackName);
674 return rc;
675}
676
677/**
678 * Verifies the manifest and its signature.
679 *
680 * @returns VBox status code, failures with message.
681 * @param hOurManifest The manifest we compiled.
682 * @param hManifestFile The manifest file in the extension pack.
683 * @param hSignatureFile The manifest signature file.
684 * @param pszError Where to store an error message on failure.
685 * @param cbError The size of the buffer @a pszError points to.
686 */
687static int vboxExtPackVerifyManifestAndSignature(RTMANIFEST hOurManifest, RTVFSFILE hManifestFile, RTVFSFILE hSignatureFile,
688 char *pszError, size_t cbError)
689{
690 /*
691 * Read the manifest from the extension pack.
692 */
693 int rc = RTVfsFileSeek(hManifestFile, 0, RTFILE_SEEK_BEGIN, NULL);
694 if (RT_FAILURE(rc))
695 return vboxExtPackReturnError(rc, pszError, cbError, "RTVfsFileSeek failed: %Rrc", rc);
696
697 RTMANIFEST hTheirManifest;
698 rc = RTManifestCreate(0 /*fFlags*/, &hTheirManifest);
699 if (RT_FAILURE(rc))
700 return vboxExtPackReturnError(rc, pszError, cbError, "RTManifestCreate failed: %Rrc", rc);
701
702 RTVFSIOSTREAM hVfsIos = RTVfsFileToIoStream(hManifestFile);
703 rc = RTManifestReadStandard(hTheirManifest, hVfsIos);
704 RTVfsIoStrmRelease(hVfsIos);
705 if (RT_SUCCESS(rc))
706 {
707 /*
708 * Compare the manifests.
709 */
710 static const char *s_apszIgnoreEntries[] =
711 {
712 VBOX_EXTPACK_MANIFEST_NAME,
713 VBOX_EXTPACK_SIGNATURE_NAME,
714 "./" VBOX_EXTPACK_MANIFEST_NAME,
715 "./" VBOX_EXTPACK_SIGNATURE_NAME,
716 NULL
717 };
718 char szError[RTPATH_MAX];
719 rc = RTManifestEqualsEx(hOurManifest, hTheirManifest, &s_apszIgnoreEntries[0], NULL,
720 RTMANIFEST_EQUALS_IGN_MISSING_ATTRS /*fFlags*/,
721 szError, sizeof(szError));
722 if (RT_SUCCESS(rc))
723 {
724 /*
725 * Validate the manifest file signature.
726 */
727 /** @todo implement signature stuff */
728 NOREF(hSignatureFile);
729
730 }
731 else if (rc == VERR_NOT_EQUAL && szError[0])
732 vboxExtPackSetError(pszError, cbError, "Manifest mismatch: %s", szError);
733 else
734 vboxExtPackSetError(pszError, cbError, "RTManifestEqualsEx failed: %Rrc", rc);
735#if 0
736 RTVFSIOSTREAM hVfsIosStdOut = NIL_RTVFSIOSTREAM;
737 RTVfsIoStrmFromStdHandle(RTHANDLESTD_OUTPUT, RTFILE_O_WRITE, true, &hVfsIosStdOut);
738 RTVfsIoStrmWrite(hVfsIosStdOut, "Our:\n", sizeof("Our:\n") - 1, true, NULL);
739 RTManifestWriteStandard(hOurManifest, hVfsIosStdOut);
740 RTVfsIoStrmWrite(hVfsIosStdOut, "Their:\n", sizeof("Their:\n") - 1, true, NULL);
741 RTManifestWriteStandard(hTheirManifest, hVfsIosStdOut);
742#endif
743 }
744 else
745 vboxExtPackSetError(pszError, cbError, "Error parsing '%s': %Rrc", VBOX_EXTPACK_MANIFEST_NAME, rc);
746
747 RTManifestRelease(hTheirManifest);
748 return rc;
749}
750
751
752/**
753 * Validates a standard file.
754 *
755 * Generally all files are
756 *
757 * @returns VBox status code, failure message in @a pszError.
758 * @param pszAdjName The adjusted member name.
759 * @param enmType The VFS object type.
760 * @param phVfsObj The pointer to the VFS object handle variable.
761 * This is both input and output.
762 * @param phVfsFile Where to store the handle to the memorized
763 * file. This is NULL for license files.
764 * @param pszError Where to write an error message on failure.
765 * @param cbError The size of the @a pszError buffer.
766 */
767static int VBoxExtPackValidateStandardFile(const char *pszAdjName, RTVFSOBJTYPE enmType,
768 PRTVFSOBJ phVfsObj, PRTVFSFILE phVfsFile, char *pszError, size_t cbError)
769{
770 int rc;
771
772 /*
773 * Make sure it's a file and that it isn't too large.
774 */
775 if (phVfsFile && *phVfsFile != NIL_RTVFSFILE)
776 rc = vboxExtPackReturnError(VERR_DUPLICATE, pszError, cbError,
777 "There can only be one '%s'", pszAdjName);
778 else if (enmType != RTVFSOBJTYPE_IO_STREAM && enmType != RTVFSOBJTYPE_FILE)
779 rc = vboxExtPackReturnError(VERR_NOT_A_FILE, pszError, cbError,
780 "Standard member '%s' is not a file", pszAdjName);
781 else
782 {
783 RTFSOBJINFO ObjInfo;
784 rc = RTVfsObjQueryInfo(*phVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
785 if (RT_SUCCESS(rc))
786 {
787 if (!RTFS_IS_FILE(ObjInfo.Attr.fMode))
788 rc = vboxExtPackReturnError(VERR_NOT_A_FILE, pszError, cbError,
789 "Standard member '%s' is not a file", pszAdjName);
790 else if (ObjInfo.cbObject >= _1M)
791 rc = vboxExtPackReturnError(VERR_OUT_OF_RANGE, pszError, cbError,
792 "Standard member '%s' is too large: %'RU64 bytes (max 1 MB)",
793 pszAdjName, (uint64_t)ObjInfo.cbObject);
794 else
795 {
796 /*
797 * Make an in memory copy of the stream and check that the file
798 * is UTF-8 clean.
799 */
800 RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(*phVfsObj);
801 RTVFSFILE hVfsFile;
802 rc = RTVfsMemorizeIoStreamAsFile(hVfsIos, RTFILE_O_READ, &hVfsFile);
803 if (RT_SUCCESS(rc))
804 {
805 rc = RTVfsIoStrmValidateUtf8Encoding(hVfsIos,
806 RTVFS_VALIDATE_UTF8_BY_RTC_3629 | RTVFS_VALIDATE_UTF8_NO_NULL,
807 NULL);
808 if (RT_SUCCESS(rc))
809 {
810 /*
811 * Replace *phVfsObj with the memorized file.
812 */
813 rc = RTVfsFileSeek(hVfsFile, 0, RTFILE_SEEK_BEGIN, NULL);
814 if (RT_SUCCESS(rc))
815 {
816 RTVfsObjRelease(*phVfsObj);
817 *phVfsObj = RTVfsObjFromFile(hVfsFile);
818 }
819 else
820 vboxExtPackSetError(pszError, cbError, "RTVfsFileSeek failed on '%s': %Rrc", pszAdjName, rc);
821 }
822
823 if (phVfsFile && RT_SUCCESS(rc))
824 *phVfsFile = hVfsFile;
825 else
826 RTVfsFileRelease(hVfsFile);
827 }
828 else
829 vboxExtPackSetError(pszError, cbError, "RTVfsMemorizeIoStreamAsFile failed on '%s': %Rrc", pszAdjName, rc);
830 RTVfsIoStrmRelease(hVfsIos);
831 }
832 }
833 else
834 vboxExtPackSetError(pszError, cbError, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszAdjName, rc);
835 }
836 return rc;
837}
838
839
840/**
841 * Validates a name in an extension pack.
842 *
843 * We restrict the charset to try make sure the extension pack can be unpacked
844 * on all file systems.
845 *
846 * @returns VBox status code, failures with message.
847 * @param pszName The name to validate.
848 * @param pszError Where to store an error message on failure.
849 * @param cbError The size of the buffer @a pszError points to.
850 */
851static int vboxExtPackValidateMemberName(const char *pszName, char *pszError, size_t cbError)
852{
853 if (RTPathStartsWithRoot(pszName))
854 return vboxExtPackReturnError(VERR_PATH_IS_NOT_RELATIVE, pszError, cbError, "'%s': starts with root spec", pszName);
855
856 const char *pszErr = NULL;
857 const char *psz = pszName;
858 int ch;
859 while ((ch = *psz) != '\0')
860 {
861 /* Character set restrictions. */
862 if (ch < 0 || ch >= 128)
863 {
864 pszErr = "Only 7-bit ASCII allowed";
865 break;
866 }
867 if (ch <= 31 || ch == 127)
868 {
869 pszErr = "No control characters are not allowed";
870 break;
871 }
872 if (ch == '\\')
873 {
874 pszErr = "Only backward slashes are not allowed";
875 break;
876 }
877 if (strchr("'\":;*?|[]<>(){}", ch))
878 {
879 pszErr = "The characters ', \", :, ;, *, ?, |, [, ], <, >, (, ), { and } are not allowed";
880 break;
881 }
882
883 /* Take the simple way out and ban all ".." sequences. */
884 if ( ch == '.'
885 && psz[1] == '.')
886 {
887 pszErr = "Double dot sequence are not allowed";
888 break;
889 }
890
891 /* Keep the tree shallow or the hardening checks will fail. */
892 if (psz - pszName > VBOX_EXTPACK_MAX_MEMBER_NAME_LENGTH)
893 {
894 pszErr = "Too long";
895 break;
896 }
897
898 /* advance */
899 psz++;
900 }
901
902 if (pszErr)
903 return vboxExtPackReturnError(VERR_INVALID_NAME, pszError, cbError,
904 "Bad member name '%s' (pos %zu): %s", pszName, (size_t)(psz - pszName), pszErr);
905 return RTEXITCODE_SUCCESS;
906}
907
908
909/**
910 * Validates a file in an extension pack.
911 *
912 * @returns VBox status code, failures with message.
913 * @param pszName The name of the file.
914 * @param hVfsObj The VFS object.
915 * @param pszError Where to store an error message on failure.
916 * @param cbError The size of the buffer @a pszError points to.
917 */
918static int vboxExtPackValidateMemberFile(const char *pszName, RTVFSOBJ hVfsObj, char *pszError, size_t cbError)
919{
920 int rc = vboxExtPackValidateMemberName(pszName, pszError, cbError);
921 if (RT_SUCCESS(rc))
922 {
923 RTFSOBJINFO ObjInfo;
924 rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
925 if (RT_SUCCESS(rc))
926 {
927 if (ObjInfo.cbObject >= 9*_1G64)
928 rc = vboxExtPackReturnError(VERR_OUT_OF_RANGE, pszError, cbError,
929 "'%s': too large (%'RU64 bytes)",
930 pszName, (uint64_t)ObjInfo.cbObject);
931 if (!RTFS_IS_FILE(ObjInfo.Attr.fMode))
932 rc = vboxExtPackReturnError(VERR_NOT_A_FILE, pszError, cbError,
933 "The alleged file '%s' has a mode mask stating otherwise (%RTfmode)",
934 pszName, ObjInfo.Attr.fMode);
935 }
936 else
937 vboxExtPackSetError(pszError, cbError, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc);
938 }
939 return rc;
940}
941
942
943/**
944 * Validates a directory in an extension pack.
945 *
946 * @returns VBox status code, failures with message.
947 * @param pszName The name of the directory.
948 * @param hVfsObj The VFS object.
949 * @param pszError Where to store an error message on failure.
950 * @param cbError The size of the buffer @a pszError points to.
951 */
952static int vboxExtPackValidateMemberDir(const char *pszName, RTVFSOBJ hVfsObj, char *pszError, size_t cbError)
953{
954 int rc = vboxExtPackValidateMemberName(pszName, pszError, cbError);
955 if (RT_SUCCESS(rc))
956 {
957 RTFSOBJINFO ObjInfo;
958 rc = RTVfsObjQueryInfo(hVfsObj, &ObjInfo, RTFSOBJATTRADD_NOTHING);
959 if (RT_SUCCESS(rc))
960 {
961 if (!RTFS_IS_DIRECTORY(ObjInfo.Attr.fMode))
962 rc = vboxExtPackReturnError(VERR_NOT_A_DIRECTORY, pszError, cbError,
963 "The alleged directory '%s' has a mode mask saying differently (%RTfmode)",
964 pszName, ObjInfo.Attr.fMode);
965 }
966 else
967 vboxExtPackSetError(pszError, cbError, "RTVfsObjQueryInfo failed on '%s': %Rrc", pszName, rc);
968 }
969 return rc;
970}
971
972/**
973 * Validates a member of an extension pack.
974 *
975 * @returns VBox status code, failures with message.
976 * @param pszName The name of the directory.
977 * @param enmType The object type.
978 * @param hVfsObj The VFS object.
979 * @param pszError Where to store an error message on failure.
980 * @param cbError The size of the buffer @a pszError points to.
981 */
982int VBoxExtPackValidateMember(const char *pszName, RTVFSOBJTYPE enmType, RTVFSOBJ hVfsObj, char *pszError, size_t cbError)
983{
984 Assert(cbError > 0);
985 *pszError = '\0';
986
987 int rc;
988 if ( enmType == RTVFSOBJTYPE_FILE
989 || enmType == RTVFSOBJTYPE_IO_STREAM)
990 rc = vboxExtPackValidateMemberFile(pszName, hVfsObj, pszError, cbError);
991 else if ( enmType == RTVFSOBJTYPE_DIR
992 || enmType == RTVFSOBJTYPE_BASE)
993 rc = vboxExtPackValidateMemberDir(pszName, hVfsObj, pszError, cbError);
994 else
995 rc = vboxExtPackReturnError(VERR_UNEXPECTED_FS_OBJ_TYPE, pszError, cbError,
996 "'%s' is not a file or directory (enmType=%d)", pszName, enmType);
997 return rc;
998}
999
1000
1001/**
1002 * Rewinds the tarball file handle and creates a gunzip | tar chain that
1003 * results in a filesystem stream.
1004 *
1005 * @returns VBox status code, failures with message.
1006 * @param hTarballFile The handle to the tarball file.
1007 * @param pszError Where to store an error message on failure.
1008 * @param cbError The size of the buffer @a pszError points to.
1009 * @param phTarFss Where to return the filesystem stream handle.
1010 */
1011int VBoxExtPackOpenTarFss(RTFILE hTarballFile, char *pszError, size_t cbError, PRTVFSFSSTREAM phTarFss)
1012{
1013 Assert(cbError > 0);
1014 *pszError = '\0';
1015 *phTarFss = NIL_RTVFSFSSTREAM;
1016
1017 /*
1018 * Rewind the file and set up a VFS chain for it.
1019 */
1020 int rc = RTFileSeek(hTarballFile, 0, RTFILE_SEEK_BEGIN, NULL);
1021 if (RT_FAILURE(rc))
1022 return vboxExtPackReturnError(rc, pszError, cbError, "Failed seeking to the start of the tarball: %Rrc", rc);
1023
1024 RTVFSIOSTREAM hTarballIos;
1025 rc = RTVfsIoStrmFromRTFile(hTarballFile, RTFILE_O_READ | RTFILE_O_DENY_WRITE | RTFILE_O_OPEN, true /*fLeaveOpen*/,
1026 &hTarballIos);
1027 if (RT_FAILURE(rc))
1028 return vboxExtPackReturnError(rc, pszError, cbError, "RTVfsIoStrmFromRTFile failed: %Rrc", rc);
1029
1030 RTVFSIOSTREAM hGunzipIos;
1031 rc = RTZipGzipDecompressIoStream(hTarballIos, 0 /*fFlags*/, &hGunzipIos);
1032 if (RT_SUCCESS(rc))
1033 {
1034 RTVFSFSSTREAM hTarFss;
1035 rc = RTZipTarFsStreamFromIoStream(hGunzipIos, 0 /*fFlags*/, &hTarFss);
1036 if (RT_SUCCESS(rc))
1037 {
1038 RTVfsIoStrmRelease(hGunzipIos);
1039 RTVfsIoStrmRelease(hTarballIos);
1040 *phTarFss = hTarFss;
1041 return VINF_SUCCESS;
1042 }
1043 vboxExtPackSetError(pszError, cbError, "RTZipTarFsStreamFromIoStream failed: %Rrc", rc);
1044 RTVfsIoStrmRelease(hGunzipIos);
1045 }
1046 else
1047 vboxExtPackSetError(pszError, cbError, "RTZipGzipDecompressIoStream failed: %Rrc", rc);
1048 RTVfsIoStrmRelease(hTarballIos);
1049 return rc;
1050}
1051
1052
1053/**
1054 * Validates the extension pack tarball prior to unpacking.
1055 *
1056 * Operations performed:
1057 * - Mandatory files.
1058 * - Manifest check.
1059 * - Manifest seal check.
1060 * - XML check, match name.
1061 *
1062 * @returns VBox status code, failures with message.
1063 * @param hTarballFile The handle to open the @a pszTarball file.
1064 * @param pszExtPackName The name of the extension pack name. NULL if
1065 * the name is not fixed.
1066 * @param pszTarball The name of the tarball in case we have to
1067 * complain about something.
1068 * @param pszError Where to store an error message on failure.
1069 * @param cbError The size of the buffer @a pszError points to.
1070 * @param phValidManifest Where to optionally return the handle to fully
1071 * validated the manifest for the extension pack.
1072 * This includes all files.
1073 * @param phXmlFile Where to optionally return the memorized XML
1074 * file.
1075 *
1076 * @todo This function is a bit too long and should be split up if possible.
1077 */
1078int VBoxExtPackValidateTarball(RTFILE hTarballFile, const char *pszExtPackName, const char *pszTarball,
1079 char *pszError, size_t cbError, PRTMANIFEST phValidManifest, PRTVFSFILE phXmlFile)
1080{
1081 /*
1082 * Clear return values.
1083 */
1084 if (phValidManifest)
1085 *phValidManifest = NIL_RTMANIFEST;
1086 if (phXmlFile)
1087 *phXmlFile = NIL_RTVFSFILE;
1088 Assert(cbError > 1);
1089 *pszError = '\0';
1090 NOREF(pszTarball);
1091
1092 /*
1093 * Open the tar.gz filesystem stream and set up an manifest in-memory file.
1094 */
1095 RTVFSFSSTREAM hTarFss;
1096 int rc = VBoxExtPackOpenTarFss(hTarballFile, pszError, cbError, &hTarFss);
1097 if (RT_FAILURE(rc))
1098 return rc;
1099
1100 RTMANIFEST hOurManifest;
1101 rc = RTManifestCreate(0 /*fFlags*/, &hOurManifest);
1102 if (RT_SUCCESS(rc))
1103 {
1104 /*
1105 * Process the tarball (would be nice to move this to a function).
1106 */
1107 RTVFSFILE hXmlFile = NIL_RTVFSFILE;
1108 RTVFSFILE hManifestFile = NIL_RTVFSFILE;
1109 RTVFSFILE hSignatureFile= NIL_RTVFSFILE;
1110 for (;;)
1111 {
1112 /*
1113 * Get the next stream object.
1114 */
1115 char *pszName;
1116 RTVFSOBJ hVfsObj;
1117 RTVFSOBJTYPE enmType;
1118 rc = RTVfsFsStrmNext(hTarFss, &pszName, &enmType, &hVfsObj);
1119 if (RT_FAILURE(rc))
1120 {
1121 if (rc != VERR_EOF)
1122 vboxExtPackSetError(pszError, cbError, "RTVfsFsStrmNext failed: %Rrc", rc);
1123 else
1124 rc = VINF_SUCCESS;
1125 break;
1126 }
1127 const char *pszAdjName = pszName[0] == '.' && pszName[1] == '/' ? &pszName[2] : pszName;
1128
1129 /*
1130 * Check the type & name validity, performing special tests on
1131 * standard extension pack member files.
1132 *
1133 * N.B. We will always reach the end of the loop before breaking on
1134 * failure - cleanup reasons.
1135 */
1136 rc = VBoxExtPackValidateMember(pszName, enmType, hVfsObj, pszError, cbError);
1137 if (RT_SUCCESS(rc))
1138 {
1139 PRTVFSFILE phVfsFile;
1140 if (!strcmp(pszAdjName, VBOX_EXTPACK_DESCRIPTION_NAME))
1141 phVfsFile = &hXmlFile;
1142 else if (!strcmp(pszAdjName, VBOX_EXTPACK_MANIFEST_NAME))
1143 phVfsFile = &hManifestFile;
1144 else if (!strcmp(pszAdjName, VBOX_EXTPACK_SIGNATURE_NAME))
1145 phVfsFile = &hSignatureFile;
1146 else if (!strncmp(pszAdjName, VBOX_EXTPACK_LICENSE_NAME_PREFIX, sizeof(VBOX_EXTPACK_LICENSE_NAME_PREFIX) - 1))
1147 rc = VBoxExtPackValidateStandardFile(pszAdjName, enmType, &hVfsObj, NULL, pszError, cbError);
1148 else
1149 phVfsFile = NULL;
1150 if (phVfsFile)
1151 rc = VBoxExtPackValidateStandardFile(pszAdjName, enmType, &hVfsObj, phVfsFile, pszError, cbError);
1152 }
1153
1154 /*
1155 * Add any I/O stream to the manifest
1156 */
1157 if ( RT_SUCCESS(rc)
1158 && ( enmType == RTVFSOBJTYPE_FILE
1159 || enmType == RTVFSOBJTYPE_IO_STREAM))
1160 {
1161 RTVFSIOSTREAM hVfsIos = RTVfsObjToIoStream(hVfsObj);
1162 rc = RTManifestEntryAddIoStream(hOurManifest, hVfsIos, pszAdjName, RTMANIFEST_ATTR_SIZE | RTMANIFEST_ATTR_SHA256);
1163 if (RT_FAILURE(rc))
1164 vboxExtPackSetError(pszError, cbError, "RTManifestEntryAddIoStream failed on '%s': %Rrc", pszAdjName, rc);
1165 RTVfsIoStrmRelease(hVfsIos);
1166 }
1167
1168 /*
1169 * Clean up and break out on failure.
1170 */
1171 RTVfsObjRelease(hVfsObj);
1172 RTStrFree(pszName);
1173 if (RT_FAILURE(rc))
1174 break;
1175 }
1176
1177 /*
1178 * If we've successfully processed the tarball, verify that the
1179 * mandatory files are present.
1180 */
1181 if (RT_SUCCESS(rc))
1182 {
1183 if (hXmlFile == NIL_RTVFSFILE)
1184 rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_DESCRIPTION_NAME);
1185 if (hManifestFile == NIL_RTVFSFILE)
1186 rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_MANIFEST_NAME);
1187 if (hSignatureFile == NIL_RTVFSFILE)
1188 rc = vboxExtPackReturnError(VERR_MISSING, pszError, cbError, "Mandator file '%s' is missing", VBOX_EXTPACK_SIGNATURE_NAME);
1189 }
1190
1191 /*
1192 * Check the manifest and it's signature.
1193 */
1194 if (RT_SUCCESS(rc))
1195 rc = vboxExtPackVerifyManifestAndSignature(hOurManifest, hManifestFile, hSignatureFile, pszError, cbError);
1196
1197 /*
1198 * Check the XML.
1199 */
1200 if (RT_SUCCESS(rc))
1201 rc = vboxExtPackVerifyXml(hXmlFile, pszExtPackName, pszError, cbError);
1202
1203 /*
1204 * Returns objects.
1205 */
1206 if (RT_SUCCESS(rc))
1207 {
1208 if (phValidManifest)
1209 {
1210 RTManifestRetain(hOurManifest);
1211 *phValidManifest = hOurManifest;
1212 }
1213 if (phXmlFile)
1214 {
1215 RTVfsFileRetain(hXmlFile);
1216 *phXmlFile = hXmlFile;
1217 }
1218 }
1219
1220 /*
1221 * Release our object references.
1222 */
1223 RTManifestRelease(hOurManifest);
1224 RTVfsFileRelease(hXmlFile);
1225 RTVfsFileRelease(hManifestFile);
1226 RTVfsFileRelease(hSignatureFile);
1227 }
1228 else
1229 vboxExtPackSetError(pszError, cbError, "RTManifestCreate failed: %Rrc", rc);
1230 RTVfsFsStrmRelease(hTarFss);
1231
1232 return rc;
1233}
1234
Note: See TracBrowser for help on using the repository browser.

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