Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1813 lines
55 KiB

  1. #include "nt.h"
  2. #include "ntdef.h"
  3. #include "ntrtl.h"
  4. #include "nturtl.h"
  5. #include "sxs-rtl.h"
  6. #include "fasterxml.h"
  7. #include "skiplist.h"
  8. #include "namespacemanager.h"
  9. #include "xmlstructure.h"
  10. #include "xmlassert.h"
  11. #include "manifestinspection.h"
  12. #include "analyzerxmldsig.h"
  13. #include "manifestcooked.h"
  14. #include "ntrtlstringandbuffer.h"
  15. #include "stdlib.h"
  16. #include "limits.h"
  17. NTSTATUS
  18. RtlpValidateXmlDeclaration(
  19. PXML_TOKENIZATION_STATE pState,
  20. PXMLDOC_THING pDocThing
  21. );
  22. //
  23. // Some strings that we'll need later
  24. //
  25. const XML_SPECIAL_STRING sc_ss_xmldecl_version_10 = MAKE_SPECIAL_STRING("1.0");
  26. const XML_SPECIAL_STRING sc_ss_xmldecl_yes = MAKE_SPECIAL_STRING("yes");
  27. const XML_SPECIAL_STRING sc_ss_xmlnamespace_default = MAKE_SPECIAL_STRING("urn:schemas-microsoft-com:asm.v1");
  28. NTSTATUS
  29. Rtl_InspectManifest_AssemblyIdentity(
  30. PXML_LOGICAL_STATE pLogicalState,
  31. PRTL_MANIFEST_CONTENT_RAW pManifestContent,
  32. PXMLDOC_THING pDocumentThing,
  33. PRTL_GROWING_LIST pAttributes,
  34. MANIFEST_ELEMENT_CALLBACK_REASON Reason,
  35. const struct _XML_ELEMENT_DEFINITION *pElementDefinition
  36. );
  37. NTSTATUS
  38. Rtl_InspectManifest_Assembly(
  39. PXML_LOGICAL_STATE pLogicalState,
  40. PRTL_MANIFEST_CONTENT_RAW pManifestContent,
  41. PXMLDOC_THING pDocumentThing,
  42. PRTL_GROWING_LIST pAttributes,
  43. MANIFEST_ELEMENT_CALLBACK_REASON Reason,
  44. const struct _XML_ELEMENT_DEFINITION *pElementDefinition
  45. );
  46. NTSTATUS
  47. Rtl_InspectManifest_File(
  48. PXML_LOGICAL_STATE pLogicalState,
  49. PRTL_MANIFEST_CONTENT_RAW pManifestContent,
  50. PXMLDOC_THING pDocumentThing,
  51. PRTL_GROWING_LIST pAttributes,
  52. MANIFEST_ELEMENT_CALLBACK_REASON Reason,
  53. const struct _XML_ELEMENT_DEFINITION *pElementDefinition
  54. );
  55. DECLARE_ELEMENT(assembly);
  56. DECLARE_ELEMENT(assembly_file);
  57. DECLARE_ELEMENT(assembly_assemblyIdentity);
  58. DECLARE_ELEMENT(assembly_description);
  59. //
  60. // The "assembly" root document element
  61. //
  62. enum {
  63. eAttribs_assembly_manifestVersion = 0,
  64. eAttribs_assembly_Count
  65. };
  66. XML_ELEMENT_DEFINITION rgs_Element_assembly =
  67. {
  68. XML_ELEMENT_FLAG_ALLOW_ANY_CHILDREN,
  69. eManifestState_assembly,
  70. NULL,
  71. &sc_ss_xmlnamespace_default,
  72. MAKE_SPECIAL_STRING("assembly"),
  73. &Rtl_InspectManifest_Assembly,
  74. rgs_Element_assembly_Children,
  75. eAttribs_assembly_Count,
  76. {
  77. { XML_ATTRIBUTE_FLAG_REQUIRED, NULL, MAKE_SPECIAL_STRING("manifestVersion") },
  78. }
  79. };
  80. PCXML_ELEMENT_DEFINITION rgs_Element_assembly_Children[] = {
  81. ELEMENT_NAMED(assembly_file),
  82. ELEMENT_NAMED(assembly_assemblyIdentity),
  83. NULL
  84. };
  85. //
  86. // The "file" element
  87. //
  88. enum {
  89. eAttribs_assembly_file_digestMethod,
  90. eAttribs_assembly_file_hash,
  91. eAttribs_assembly_file_hashalg,
  92. eAttribs_assembly_file_loadFrom,
  93. eAttribs_assembly_file_name,
  94. eAttribs_assembly_file_size,
  95. eAttribs_assembly_file_Count
  96. };
  97. ELEMENT_DEFINITION_DEFNS(assembly, file, Rtl_InspectManifest_File, XML_ELEMENT_FLAG_ALLOW_ANY_CHILDREN)
  98. ATTRIBUTE_DEFINITION_NONS_NODEFAULT(digestMethod),
  99. ATTRIBUTE_DEFINITION_NONS_NODEFAULT(hash),
  100. ATTRIBUTE_DEFINITION_NONS_NODEFAULT(hashalg),
  101. ATTRIBUTE_DEFINITION_NONS_NODEFAULT(loadFrom),
  102. ATTRIBUTE_DEFINITION_NONS_NODEFAULT(name),
  103. ATTRIBUTE_DEFINITION_NONS_NODEFAULT(size),
  104. ELEMENT_DEFINITION_DEFNS_END();
  105. ELEMENT_DEFINITION_CHILD_ELEMENTS(assembly, file)
  106. ELEMENT_DEFINITION_CHILD_ELEMENTS_END();
  107. int unscrew_si[] = {3};
  108. //
  109. // Assembly identities
  110. //
  111. enum {
  112. eAttribs_assembly_assemblyIdentity_language = 0,
  113. eAttribs_assembly_assemblyIdentity_name,
  114. eAttribs_assembly_assemblyIdentity_processorArchitecture,
  115. eAttribs_assembly_assemblyIdentity_publicKeyToken,
  116. eAttribs_assembly_assemblyIdentity_type,
  117. eAttribs_assembly_assemblyIdentity_version,
  118. eAttribs_assembly_assemblyIdentity_Count
  119. };
  120. ELEMENT_DEFINITION_DEFNS(assembly, assemblyIdentity, Rtl_InspectManifest_AssemblyIdentity, XML_ELEMENT_FLAG_NO_ELEMENTS | XML_ELEMENT_FLAG_ALLOW_ANY_ATTRIBUTES)
  121. ATTRIBUTE_DEFINITION_NONS_NODEFAULT(empty),
  122. ELEMENT_DEFINITION_DEFNS_END();
  123. // This is an "extendo-element" - all attributes here are legal, some are just more legal than others.
  124. ELEMENT_DEFINITION_CHILD_ELEMENTS(assembly, assemblyIdentity)
  125. ELEMENT_DEFINITION_CHILD_ELEMENTS_END();
  126. // Please leave this in ... my poor editor has issues with the above for some reason
  127. int unconfuse_sourceinsight[] = {4};
  128. PCXML_ELEMENT_DEFINITION
  129. RtlpFindElementInDefinition(
  130. PCXML_ELEMENT_DEFINITION CurrentNode,
  131. PXML_TOKENIZATION_STATE TokenizerState,
  132. PXMLDOC_ELEMENT FoundElement
  133. )
  134. {
  135. ULONG i = 0;
  136. PCXML_ELEMENT_DEFINITION ThisChild;
  137. BOOLEAN fMatches;
  138. NTSTATUS status;
  139. //
  140. // Technically this isn't an error, but let's not give them any ideas
  141. //
  142. if (CurrentNode->ChildElements == NULL)
  143. return NULL;
  144. while (TRUE) {
  145. ThisChild = CurrentNode->ChildElements[i];
  146. if (ThisChild == NULL)
  147. break;
  148. status = RtlXmlMatchLogicalElement(
  149. TokenizerState,
  150. FoundElement,
  151. ThisChild->Namespace,
  152. &ThisChild->Name,
  153. &fMatches);
  154. if (!NT_SUCCESS(status)) {
  155. return NULL;
  156. }
  157. else if (fMatches) {
  158. break;
  159. }
  160. i++;
  161. }
  162. return (fMatches ? CurrentNode->ChildElements[i] : NULL);
  163. }
  164. //
  165. // The meat of the matter
  166. //
  167. NTSTATUS
  168. RtlInspectManifestStream(
  169. ULONG ulFlags,
  170. PVOID pvManifest,
  171. SIZE_T cbManifest,
  172. PRTL_MANIFEST_CONTENT_RAW pContent,
  173. PXML_TOKENIZATION_STATE pTargetTokenState
  174. )
  175. {
  176. NTSTATUS status = STATUS_SUCCESS;
  177. XML_LOGICAL_STATE ParseState;
  178. BOOLEAN fFoundAssemblyTag = FALSE;
  179. NS_MANAGER Namespaces;
  180. RTL_GROWING_LIST Attributes;
  181. ULONG ulHitElement;
  182. XMLDOC_THING LogicalPiece;
  183. PCXML_ELEMENT_DEFINITION CurrentElement = NULL;
  184. PCXML_ELEMENT_DEFINITION DocumentRoot = ELEMENT_NAMED(assembly);
  185. PCXML_ELEMENT_DEFINITION FloatingElementParent = NULL;
  186. PCXML_ELEMENT_DEFINITION FloatingElement = NULL;
  187. //
  188. // Must give us a pointer to the manifest, a content structure to fill out, and a
  189. // hashing context w/callback.
  190. //
  191. if ((pvManifest == NULL) || (pContent == NULL))
  192. return STATUS_INVALID_PARAMETER;
  193. //
  194. // Do normal startup-type stuff
  195. //
  196. status = RtlXmlInitializeNextLogicalThing(&ParseState, pvManifest, cbManifest, &g_DefaultAllocator);
  197. if (!NT_SUCCESS(status))
  198. goto Exit;
  199. status = RtlInitializeGrowingList(&Attributes, sizeof(XMLDOC_ATTRIBUTE), 20, NULL, 0, &g_DefaultAllocator);
  200. if (!NT_SUCCESS(status))
  201. goto Exit;
  202. status = RtlNsInitialize(&Namespaces, RtlXmlDefaultCompareStrings, &ParseState.ParseState, &g_DefaultAllocator);
  203. if (!NT_SUCCESS(status))
  204. goto Exit;
  205. //
  206. // See if we've got an xmldecl
  207. //
  208. status = RtlXmlNextLogicalThing(&ParseState, &Namespaces, &LogicalPiece, &Attributes);
  209. if (!NT_SUCCESS(status))
  210. goto Exit;
  211. //
  212. // Validate the first thing in the document. It's either an xmldecl or the <assembly> element,
  213. // both of which are validatable.
  214. //
  215. if (LogicalPiece.ulThingType == XMLDOC_THING_XMLDECL) {
  216. status = RtlpValidateXmlDeclaration(&ParseState.ParseState, &LogicalPiece);
  217. if (!NT_SUCCESS(status))
  218. goto Exit;
  219. }
  220. //
  221. // If it's an element, then it must be the <assembly> element.
  222. //
  223. else if (LogicalPiece.ulThingType == XMLDOC_THING_ELEMENT) {
  224. fFoundAssemblyTag = TRUE;
  225. }
  226. //
  227. // If we've found the assembly tag, then we should set our original document state to
  228. // being the Assembly state, rather than the DocumentRoot state.
  229. //
  230. if (fFoundAssemblyTag) {
  231. CurrentElement = DocumentRoot;
  232. }
  233. //
  234. // Now let's zip through all the elements we find, using the filter along the way.
  235. //
  236. while (TRUE) {
  237. status = RtlXmlNextLogicalThing(&ParseState, &Namespaces, &LogicalPiece, &Attributes);
  238. if (!NT_SUCCESS(status))
  239. goto Exit;
  240. if (LogicalPiece.ulThingType == XMLDOC_THING_ELEMENT) {
  241. // Special case - this is the first element we've found, so we have to make sure
  242. // it matches the supposed document root
  243. if (CurrentElement == NULL) {
  244. CurrentElement = DocumentRoot;
  245. if (CurrentElement->pfnWorkerCallback) {
  246. status = (*CurrentElement->pfnWorkerCallback)(
  247. &ParseState,
  248. pContent,
  249. &LogicalPiece,
  250. &Attributes,
  251. eElementNotify_Open,
  252. CurrentElement);
  253. if (!NT_SUCCESS(status))
  254. goto Exit;
  255. }
  256. }
  257. else {
  258. PCXML_ELEMENT_DEFINITION NextElement;
  259. NextElement = RtlpFindElementInDefinition(
  260. CurrentElement,
  261. &ParseState.ParseState,
  262. &LogicalPiece.Element);
  263. //
  264. // Look in the small list of valid "floating" fragments
  265. //
  266. if ((NextElement == NULL) && (FloatingElementParent == NULL)) {
  267. PCXML_ELEMENT_DEFINITION SignatureElement = ELEMENT_NAMED(Signature);
  268. BOOLEAN fMatches = FALSE;
  269. status = RtlXmlMatchLogicalElement(
  270. &ParseState.ParseState,
  271. &LogicalPiece.Element,
  272. SignatureElement->Namespace,
  273. &SignatureElement->Name,
  274. &fMatches);
  275. if (!NT_SUCCESS(status))
  276. goto Exit;
  277. if (fMatches) {
  278. FloatingElementParent = CurrentElement;
  279. FloatingElement = SignatureElement;
  280. NextElement = SignatureElement;
  281. }
  282. }
  283. //
  284. // If we didn't find an element, this might be the 'signature' element.
  285. // See if we're looking for signatures, and if so, set the "next element" to be
  286. // the Signature element and continue looping.
  287. //
  288. if (NextElement == NULL) {
  289. if (CurrentElement->ulFlags & XML_ELEMENT_FLAG_ALLOW_ANY_CHILDREN) {
  290. // TODO: There ought to be some default callback, but for now, skip ahead
  291. // in the document until we find the close of this new child, then continue
  292. // in the current context as if nothing happened.
  293. status = RtlXmlSkipElement(&ParseState, &LogicalPiece.Element);
  294. if (!NT_SUCCESS(status))
  295. goto Exit;
  296. }
  297. else {
  298. // TODO: Report an error here
  299. status = STATUS_UNSUCCESSFUL;
  300. goto Exit;
  301. }
  302. }
  303. //
  304. // Otherwise, this is a valid child element, so call its worker
  305. //
  306. else {
  307. if (NextElement->pfnWorkerCallback) {
  308. status = (*NextElement->pfnWorkerCallback)(
  309. &ParseState,
  310. pContent,
  311. &LogicalPiece,
  312. &Attributes,
  313. eElementNotify_Open,
  314. NextElement);
  315. if (!NT_SUCCESS(status)) {
  316. // TODO: Report an error here
  317. goto Exit;
  318. }
  319. }
  320. //
  321. // Spiffy, let's go move into this new state, if that's
  322. // what we're supposed to do. Empty elements don't affect
  323. // the state of the world at all.
  324. //
  325. if (!LogicalPiece.Element.fElementEmpty)
  326. CurrentElement = NextElement;
  327. else
  328. {
  329. //
  330. // Notify this element that we're closing it.
  331. //
  332. if (NextElement->pfnWorkerCallback) {
  333. status = (*NextElement->pfnWorkerCallback)(
  334. &ParseState,
  335. pContent,
  336. &LogicalPiece,
  337. &Attributes,
  338. eElementNotify_Close,
  339. NextElement);
  340. if (!NT_SUCCESS(status)) {
  341. // TODO: Log an error here saying the callback failed
  342. goto Exit;
  343. }
  344. }
  345. }
  346. }
  347. }
  348. }
  349. // Found the end of the current element. "Pop" it by walking up one on
  350. // the stack
  351. else if (LogicalPiece.ulThingType == XMLDOC_THING_END_ELEMENT) {
  352. if ((CurrentElement->ParentElement == NULL) && (FloatingElementParent == NULL)) {
  353. // TODO: We found the end of this document structure, stop
  354. // looking for more elements.
  355. break;
  356. }
  357. else {
  358. if (CurrentElement->pfnWorkerCallback) {
  359. status = (*CurrentElement->pfnWorkerCallback)(
  360. &ParseState,
  361. pContent,
  362. &LogicalPiece,
  363. &Attributes,
  364. eElementNotify_Close,
  365. CurrentElement);
  366. if (!NT_SUCCESS(status)) {
  367. // TODO: Log an error here saying the callback failed
  368. goto Exit;
  369. }
  370. }
  371. if (FloatingElementParent && (CurrentElement == FloatingElement)) {
  372. CurrentElement = FloatingElementParent;
  373. FloatingElementParent = NULL;
  374. FloatingElement = NULL;
  375. }
  376. else {
  377. CurrentElement = CurrentElement->ParentElement;
  378. }
  379. }
  380. }
  381. // PCData in the input? Ok, if the element allows it
  382. else if (LogicalPiece.ulThingType == XMLDOC_THING_HYPERSPACE) {
  383. if (CurrentElement && CurrentElement->ulFlags & XML_ELEMENT_FLAG_NO_PCDATA) {
  384. // TODO: Issue an error here
  385. status = STATUS_UNSUCCESSFUL;
  386. goto Exit;
  387. }
  388. else {
  389. if (CurrentElement && (CurrentElement->pfnWorkerCallback)) {
  390. status = (*CurrentElement->pfnWorkerCallback)(
  391. &ParseState,
  392. pContent,
  393. &LogicalPiece,
  394. &Attributes,
  395. eElementNotify_Hyperspace,
  396. CurrentElement);
  397. if (!NT_SUCCESS(status)) {
  398. // TODO: Log an error here saying the callback failed
  399. goto Exit;
  400. }
  401. }
  402. }
  403. }
  404. // Error in the input stream? Ok, stop.
  405. else if (LogicalPiece.ulThingType == XMLDOC_THING_ERROR) {
  406. // TODO: Issue an error here
  407. status = LogicalPiece.Error.Code;
  408. goto Exit;
  409. }
  410. // End of stream? Spiffy, we're done
  411. else if (LogicalPiece.ulThingType == XMLDOC_THING_END_OF_STREAM) {
  412. break;
  413. }
  414. }
  415. status = RtlXmlCloneTokenizationState(&ParseState.ParseState, pTargetTokenState);
  416. if (!NT_SUCCESS(status))
  417. goto Exit;
  418. Exit:
  419. RtlXmlDestroyNextLogicalThing(&ParseState);
  420. RtlDestroyGrowingList(&Attributes);
  421. return status;
  422. }
  423. NTSTATUS
  424. RtlpValidateXmlDeclaration(
  425. PXML_TOKENIZATION_STATE pState,
  426. PXMLDOC_THING pDocThing
  427. )
  428. {
  429. NTSTATUS status = STATUS_SUCCESS;
  430. XML_STRING_COMPARE fMatch;
  431. if ((pState == NULL) || (pDocThing == NULL)) {
  432. return STATUS_INVALID_PARAMETER;
  433. }
  434. else if (pDocThing->ulThingType != XMLDOC_THING_XMLDECL) {
  435. return STATUS_MANIFEST_MISSING_XML_DECL;
  436. }
  437. status = pState->pfnCompareSpecialString(
  438. pState,
  439. &pDocThing->XmlDecl.Standalone,
  440. &sc_ss_xmldecl_yes,
  441. &fMatch);
  442. if (!NT_SUCCESS(status)) {
  443. return status;
  444. }
  445. else if (fMatch != XML_STRING_COMPARE_EQUALS) {
  446. return STATUS_MANIFEST_NOT_STANDALONE;
  447. }
  448. status = pState->pfnCompareSpecialString(
  449. pState,
  450. &pDocThing->XmlDecl.Version,
  451. &sc_ss_xmldecl_version_10,
  452. &fMatch);
  453. if (!NT_SUCCESS(status)) {
  454. return status;
  455. }
  456. else if (fMatch != XML_STRING_COMPARE_EQUALS) {
  457. return STATUS_MANIFEST_NOT_VERSION_1_0;
  458. }
  459. return STATUS_SUCCESS;
  460. }
  461. typedef struct _SEARCH_ATTRIBUTES_CONTEXT {
  462. PXML_TOKENIZATION_STATE State;
  463. PXMLDOC_ATTRIBUTE SearchKey;
  464. } SEARCH_ATTRIBUTES_CONTEXT;
  465. typedef int (__cdecl *bsearchcompare)(const void*, const void*);
  466. int __cdecl SearchForAttribute(
  467. const SEARCH_ATTRIBUTES_CONTEXT* Context,
  468. PCXML_VALID_ELEMENT_ATTRIBUTE ValidAttribute
  469. )
  470. {
  471. XML_STRING_COMPARE Compare;
  472. RtlXmlMatchAttribute(
  473. Context->State,
  474. Context->SearchKey,
  475. ValidAttribute->Attribute.Namespace,
  476. &ValidAttribute->Attribute.Name,
  477. &Compare);
  478. //
  479. // Note: this logic is intentionally backwards.
  480. //
  481. return -(int)Compare;
  482. }
  483. NTSTATUS
  484. RtlValidateAttributesAndOrganize(
  485. PXML_TOKENIZATION_STATE State,
  486. PXMLDOC_ELEMENT Element,
  487. PRTL_GROWING_LIST Attributes,
  488. PCXML_ELEMENT_DEFINITION ThisElement,
  489. PXMLDOC_ATTRIBUTE *OrderedList
  490. )
  491. {
  492. NTSTATUS status = STATUS_SUCCESS;
  493. ULONG ul;
  494. BOOLEAN Compare;
  495. PXMLDOC_ATTRIBUTE pThisAttribute;
  496. SEARCH_ATTRIBUTES_CONTEXT SearchContext = { State };
  497. RtlZeroMemory(OrderedList, ThisElement->AttributeCount * sizeof(PXMLDOC_ATTRIBUTE));
  498. for (ul = 0; ul < Element->ulAttributeCount; ul++) {
  499. PCXML_VALID_ELEMENT_ATTRIBUTE MatchingAttribute = NULL;
  500. status = RtlIndexIntoGrowingList(
  501. Attributes,
  502. ul,
  503. (PVOID*)&SearchContext.SearchKey,
  504. FALSE);
  505. if (!NT_SUCCESS(status))
  506. goto Exit;
  507. MatchingAttribute = bsearch(
  508. &SearchContext,
  509. ThisElement->AttributeList,
  510. ThisElement->AttributeCount,
  511. sizeof(ThisElement->AttributeList[0]),
  512. (bsearchcompare)SearchForAttribute);
  513. if (MatchingAttribute) {
  514. // TODO: Fix this up a little bit so that we can call off to the validator
  515. OrderedList[MatchingAttribute - ThisElement->AttributeList] = SearchContext.SearchKey;
  516. }
  517. }
  518. status = STATUS_SUCCESS;
  519. Exit:
  520. return status;
  521. }
  522. static XML_SPECIAL_STRING s_us_ValidManifestVersions[] = {
  523. MAKE_SPECIAL_STRING("1.0"),
  524. MAKE_SPECIAL_STRING("1.5")
  525. };
  526. NTSTATUS
  527. Rtl_InspectManifest_Assembly(
  528. PXML_LOGICAL_STATE pLogicalState,
  529. PRTL_MANIFEST_CONTENT_RAW pManifestContent,
  530. PXMLDOC_THING pDocumentThing,
  531. PRTL_GROWING_LIST pAttributes,
  532. MANIFEST_ELEMENT_CALLBACK_REASON Reason,
  533. const struct _XML_ELEMENT_DEFINITION *pElementDefinition
  534. )
  535. {
  536. NTSTATUS status;
  537. ULONG u;
  538. PXMLDOC_ATTRIBUTE FoundAttributes[eAttribs_assembly_Count];
  539. //
  540. // Potentially this should be an ASSERT with an INTERNAL_ERROR_CHECK, since this function
  541. // has internal-only linkage.
  542. //
  543. if (!pLogicalState || !pManifestContent || !pDocumentThing || !pAttributes || !pElementDefinition)
  544. return STATUS_INVALID_PARAMETER;
  545. //
  546. // We don't care about anything other than 'open' tha
  547. //
  548. if (Reason != eElementNotify_Open)
  549. return STATUS_SUCCESS;
  550. ASSERT(pDocumentThing->ulThingType == XMLDOC_THING_ELEMENT);
  551. status = RtlValidateAttributesAndOrganize(
  552. &pLogicalState->ParseState,
  553. &pDocumentThing->Element,
  554. pAttributes,
  555. pElementDefinition,
  556. FoundAttributes);
  557. //
  558. // Log a parse error here
  559. //
  560. if (!NT_SUCCESS(status)) {
  561. goto Exit;
  562. }
  563. status = STATUS_SUCCESS;
  564. Exit:
  565. return status;
  566. }
  567. NTSTATUS
  568. Rtl_InspectManifest_File(
  569. PXML_LOGICAL_STATE pLogicalState,
  570. PRTL_MANIFEST_CONTENT_RAW pManifestContent,
  571. PXMLDOC_THING pDocumentThing,
  572. PRTL_GROWING_LIST pAttributes,
  573. MANIFEST_ELEMENT_CALLBACK_REASON Reason,
  574. const struct _XML_ELEMENT_DEFINITION *pElementDefinition
  575. )
  576. {
  577. NTSTATUS status = STATUS_SUCCESS;
  578. ULONG ulLeftovers;
  579. union {
  580. PXMLDOC_ATTRIBUTE File[eAttribs_assembly_file_Count];
  581. } Attributes;
  582. if (Reason != eElementNotify_Open)
  583. return STATUS_SUCCESS;
  584. ASSERT(pDocumentThing->ulThingType == XMLDOC_THING_ELEMENT);
  585. if (pDocumentThing->ulThingType != XMLDOC_THING_ELEMENT)
  586. return STATUS_INTERNAL_ERROR;
  587. if (pElementDefinition == ELEMENT_NAMED(assembly_file)) {
  588. ULONG ulIndex = pManifestContent->ulFileMembers;
  589. PASSEMBLY_MEMBER_FILE_RAW pNewFile = NULL;
  590. status = RtlValidateAttributesAndOrganize(
  591. &pLogicalState->ParseState,
  592. &pDocumentThing->Element,
  593. pAttributes,
  594. pElementDefinition,
  595. Attributes.File);
  596. // Log a parse error here
  597. if (!NT_SUCCESS(status)) {
  598. goto Exit;
  599. }
  600. // Log a parse error here as well
  601. if (Attributes.File[eAttribs_assembly_file_name] == NULL) {
  602. status = STATUS_MANIFEST_FILE_TAG_MISSING_NAME;
  603. goto Exit;
  604. }
  605. status = RtlIndexIntoGrowingList(&pManifestContent->FileMembers, ulIndex, (PVOID*)&pNewFile, TRUE);
  606. if (!NT_SUCCESS(status))
  607. goto Exit;
  608. RtlZeroMemory(pNewFile, sizeof(*pNewFile));
  609. if (Attributes.File[eAttribs_assembly_file_name])
  610. pNewFile->FileName = Attributes.File[eAttribs_assembly_file_name]->Value;
  611. if (Attributes.File[eAttribs_assembly_file_hashalg])
  612. pNewFile->HashAlg = Attributes.File[eAttribs_assembly_file_hashalg]->Value;
  613. if (Attributes.File[eAttribs_assembly_file_size])
  614. pNewFile->Size = Attributes.File[eAttribs_assembly_file_size]->Value;
  615. if (Attributes.File[eAttribs_assembly_file_hash])
  616. pNewFile->HashValue = Attributes.File[eAttribs_assembly_file_hash]->Value;
  617. if (Attributes.File[eAttribs_assembly_file_loadFrom])
  618. pNewFile->LoadFrom = Attributes.File[eAttribs_assembly_file_loadFrom]->Value;
  619. if (Attributes.File[eAttribs_assembly_file_digestMethod])
  620. pNewFile->DigestMethod = Attributes.File[eAttribs_assembly_file_digestMethod]->Value;
  621. pManifestContent->ulFileMembers++;
  622. }
  623. status = STATUS_SUCCESS;
  624. Exit:
  625. return status;
  626. }
  627. NTSTATUS
  628. Rtl_InspectManifest_AssemblyIdentity(
  629. PXML_LOGICAL_STATE pLogicalState,
  630. PRTL_MANIFEST_CONTENT_RAW pManifestContent,
  631. PXMLDOC_THING pDocumentThing,
  632. PRTL_GROWING_LIST pAttributes,
  633. MANIFEST_ELEMENT_CALLBACK_REASON Reason,
  634. const struct _XML_ELEMENT_DEFINITION *pElementDefinition
  635. )
  636. {
  637. NTSTATUS status = STATUS_SUCCESS;
  638. PXMLDOC_ATTRIBUTE AsmIdentAttribs[eAttribs_assembly_assemblyIdentity_Count];
  639. ULONG ulThisIdentity, ulThisAttribute, i;
  640. if (Reason != eElementNotify_Open)
  641. return STATUS_SUCCESS;
  642. ASSERT(pDocumentThing && (pDocumentThing->ulThingType == XMLDOC_THING_ELEMENT));
  643. if (!pDocumentThing || (pDocumentThing->ulThingType != XMLDOC_THING_ELEMENT))
  644. return STATUS_INTERNAL_ERROR;
  645. if (pElementDefinition == ELEMENT_NAMED(assembly_assemblyIdentity)) {
  646. if (pManifestContent->ulRootIdentityIndex != INVALID_ASSEMBLY_IDENTITY_INDEX) {
  647. // TODO: Log a parse error
  648. status = STATUS_UNSUCCESSFUL;
  649. goto Exit;
  650. }
  651. }
  652. //
  653. // Use local copies - we'll update the values in the raw content when we've
  654. // added them all.
  655. //
  656. ulThisIdentity = pManifestContent->ulAssemblyIdentitiesFound;
  657. ulThisAttribute = pManifestContent->ulAssemblyIdentityAttributes;
  658. //
  659. // For each, create slots to hold the assembly identities
  660. //
  661. for (i = 0; i < pDocumentThing->Element.ulAttributeCount; i++) {
  662. PXMLDOC_ATTRIBUTE pThisAttribute = NULL;
  663. PASSEMBLY_IDENTITY_ATTRIBUTE_RAW pRawIdent = NULL;
  664. status = RtlIndexIntoGrowingList(pAttributes, i, (PVOID*)&pThisAttribute, FALSE);
  665. if (!NT_SUCCESS(status))
  666. goto Exit;
  667. status = RtlIndexIntoGrowingList(
  668. &pManifestContent->AssemblyIdentityAttributes,
  669. ulThisAttribute++,
  670. (PVOID*)&pRawIdent,
  671. TRUE);
  672. if (!NT_SUCCESS(status))
  673. goto Exit;
  674. pRawIdent->Namespace = pThisAttribute->NsPrefix;
  675. pRawIdent->Attribute = pThisAttribute->Name;
  676. pRawIdent->Value = pThisAttribute->Value;
  677. pRawIdent->ulIdentityIndex = ulThisIdentity;
  678. }
  679. //
  680. // Whee, we got to the end and added them all - update stuff in the raw content
  681. // so that it knows all about this new identity, and mark it as root if it is.
  682. //
  683. if (pElementDefinition == ELEMENT_NAMED(assembly_assemblyIdentity)) {
  684. pManifestContent->ulRootIdentityIndex = ulThisIdentity;
  685. }
  686. pManifestContent->ulAssemblyIdentitiesFound++;
  687. pManifestContent->ulAssemblyIdentityAttributes = ulThisAttribute;
  688. status = STATUS_SUCCESS;
  689. Exit:
  690. return status;
  691. }
  692. NTSTATUS
  693. RtlSxsInitializeManifestRawContent(
  694. ULONG ulRequestedContent,
  695. PRTL_MANIFEST_CONTENT_RAW *pRawContentOut,
  696. PVOID pvOriginalBuffer,
  697. SIZE_T cbOriginalBuffer
  698. )
  699. {
  700. PRTL_MANIFEST_CONTENT_RAW pContent = NULL;
  701. PRTL_MINI_HEAP pExtraContent = NULL;
  702. PVOID pvBufferUsed = NULL;
  703. SIZE_T cbBufferUsed = 0;
  704. NTSTATUS status = STATUS_SUCCESS;
  705. RTL_ALLOCATOR MiniAllocator = { RtlMiniHeapAlloc, RtlMiniHeapFree };
  706. if (pRawContentOut)
  707. *pRawContentOut = NULL;
  708. if (!pRawContentOut || (!pvOriginalBuffer && cbOriginalBuffer))
  709. return STATUS_INVALID_PARAMETER;
  710. if (pvOriginalBuffer == NULL) {
  711. //
  712. // If you get a compile error on this line, you'll need to increase the size
  713. // of the 'default' allocation size above.
  714. //
  715. C_ASSERT(DEFAULT_MINI_HEAP_SIZE >= (sizeof(RTL_MANIFEST_CONTENT_RAW) + sizeof(RTL_MINI_HEAP)));
  716. cbBufferUsed = DEFAULT_MINI_HEAP_SIZE;
  717. status = g_DefaultAllocator.pfnAlloc(DEFAULT_MINI_HEAP_SIZE, &pvBufferUsed, g_DefaultAllocator.pvContext);
  718. if (!NT_SUCCESS(status))
  719. return status;
  720. }
  721. else {
  722. pvBufferUsed = pvOriginalBuffer;
  723. cbBufferUsed = cbOriginalBuffer;
  724. }
  725. //
  726. // Ensure there's enough space for the raw content data, as well as the extra content
  727. //
  728. if (cbBufferUsed < (sizeof(RTL_MANIFEST_CONTENT_RAW) + sizeof(RTL_MINI_HEAP))) {
  729. return STATUS_BUFFER_TOO_SMALL;
  730. }
  731. //
  732. // Set up the content structure and the extra turdlet content at
  733. // the end properly
  734. //
  735. pContent = (PRTL_MANIFEST_CONTENT_RAW)pvBufferUsed;
  736. status = RtlInitializeMiniHeapInPlace(
  737. (PRTL_MINI_HEAP)(pContent + 1),
  738. cbBufferUsed - sizeof(*pContent),
  739. &pExtraContent);
  740. if (!NT_SUCCESS(status))
  741. goto Exit;
  742. //
  743. // Now let's go initialize the content data
  744. //
  745. RtlZeroMemory(pContent, sizeof(*pContent));
  746. pContent->ulFlags = MANIFEST_CONTENT_SELF_ALLOCATED;
  747. pContent->ulRootIdentityIndex = MAX_ULONG;
  748. MiniAllocator.pvContext = pExtraContent;
  749. status = RtlInitializeGrowingList(
  750. &pContent->FileMembers,
  751. sizeof(ASSEMBLY_MEMBER_FILE_RAW),
  752. 8,
  753. NULL,
  754. 0,
  755. &MiniAllocator);
  756. if (!NT_SUCCESS(status))
  757. goto Exit;
  758. //
  759. // Always also need the assembly identity at the root
  760. //
  761. status = RtlInitializeGrowingList(
  762. &pContent->AssemblyIdentityAttributes,
  763. sizeof(ASSEMBLY_IDENTITY_ATTRIBUTE_RAW),
  764. 8,
  765. NULL,
  766. 0,
  767. &MiniAllocator);
  768. if (!NT_SUCCESS(status))
  769. goto Exit;
  770. //
  771. // Want the COM class data?
  772. //
  773. if (ulRequestedContent & RTLIMS_GATHER_COMCLASSES) {
  774. status = RtlAllocateGrowingList(
  775. &pContent->pComClasses,
  776. sizeof(COMCLASS_REDIRECTION_RAW),
  777. &MiniAllocator);
  778. if (!NT_SUCCESS(status))
  779. goto Exit;
  780. }
  781. //
  782. // Want the window class data?
  783. //
  784. if (ulRequestedContent & RTLIMS_GATHER_WINDOWCLASSES) {
  785. status = RtlAllocateGrowingList(
  786. &pContent->pWindowClasses,
  787. sizeof(WINDOWCLASS_REDIRECTION_RAW),
  788. &MiniAllocator);
  789. if (!NT_SUCCESS(status))
  790. goto Exit;
  791. }
  792. //
  793. // Want the prog ids?
  794. //
  795. if (ulRequestedContent & RTLIMS_GATHER_COMCLASS_PROGIDS) {
  796. status = RtlAllocateGrowingList(
  797. &pContent->pProgIds,
  798. sizeof(COMCLASS_PROGID_RAW),
  799. &MiniAllocator);
  800. if (!NT_SUCCESS(status))
  801. goto Exit;
  802. }
  803. //
  804. // Want the dependencies?
  805. //
  806. if (ulRequestedContent & RTLIMS_GATHER_DEPENDENCIES) {
  807. status = RtlAllocateGrowingList(
  808. &pContent->pComClasses,
  809. sizeof(COMCLASS_REDIRECTION_RAW),
  810. &MiniAllocator);
  811. if (!NT_SUCCESS(status))
  812. goto Exit;
  813. }
  814. //
  815. // Want the external proxy stubs?
  816. //
  817. if (ulRequestedContent & RTLIMS_GATHER_EXTERNALPROXIES) {
  818. status = RtlAllocateGrowingList(
  819. &pContent->pExternalInterfaceProxyStubs,
  820. sizeof(COMINTERFACE_REDIRECTION_RAW),
  821. &MiniAllocator);
  822. if (!NT_SUCCESS(status))
  823. goto Exit;
  824. }
  825. //
  826. // Want the internal proxy stubs?
  827. //
  828. if (ulRequestedContent & RTLIMS_GATHER_INTERFACEPROXIES) {
  829. status = RtlAllocateGrowingList(
  830. &pContent->pInterfaceProxyStubs,
  831. sizeof(COMINTERFACE_REDIRECTION_RAW),
  832. &MiniAllocator);
  833. if (!NT_SUCCESS(status))
  834. goto Exit;
  835. }
  836. //
  837. // Want the type libraries?
  838. //
  839. if (ulRequestedContent & RTLIMS_GATHER_TYPELIBRARIES) {
  840. status = RtlAllocateGrowingList(
  841. &pContent->pTypeLibraries,
  842. sizeof(TYPELIB_REDIRECT_RAW),
  843. &MiniAllocator);
  844. if (!NT_SUCCESS(status))
  845. goto Exit;
  846. }
  847. if (ulRequestedContent & RTLIMS_GATHER_SIGNATURES) {
  848. status = RtlAllocateGrowingList(
  849. &pContent->pManifestSignatures,
  850. sizeof(XML_DSIG_BLOCK),
  851. &MiniAllocator);
  852. if (!NT_SUCCESS(status))
  853. goto Exit;
  854. }
  855. *pRawContentOut = pContent;
  856. Exit:
  857. if (!NT_SUCCESS(status) && pvBufferUsed && (pvBufferUsed != pvOriginalBuffer)) {
  858. g_DefaultAllocator.pfnFree(pvBufferUsed, NULL);
  859. }
  860. return status;
  861. }
  862. NTSTATUS
  863. RtlSxsDestroyManifestContent(
  864. PRTL_MANIFEST_CONTENT_RAW pRawContent
  865. )
  866. {
  867. if (!pRawContent)
  868. return STATUS_INVALID_PARAMETER;
  869. if (pRawContent->pComClasses) {
  870. RtlDestroyGrowingList(pRawContent->pComClasses);
  871. pRawContent->pComClasses = NULL;
  872. }
  873. if (pRawContent->pExternalInterfaceProxyStubs) {
  874. RtlDestroyGrowingList(pRawContent->pExternalInterfaceProxyStubs);
  875. pRawContent->pExternalInterfaceProxyStubs = NULL;
  876. }
  877. if (pRawContent->pInterfaceProxyStubs) {
  878. RtlDestroyGrowingList(pRawContent->pInterfaceProxyStubs);
  879. pRawContent->pInterfaceProxyStubs = NULL;
  880. }
  881. if (pRawContent->pManifestSignatures) {
  882. RtlDestroyGrowingList(pRawContent->pManifestSignatures);
  883. pRawContent->pManifestSignatures = NULL;
  884. }
  885. if (pRawContent->pProgIds) {
  886. RtlDestroyGrowingList(pRawContent->pProgIds);
  887. pRawContent->pProgIds = NULL;
  888. }
  889. if (pRawContent->pTypeLibraries) {
  890. RtlDestroyGrowingList(pRawContent->pTypeLibraries);
  891. pRawContent->pTypeLibraries = NULL;
  892. }
  893. if (pRawContent->pWindowClasses) {
  894. RtlDestroyGrowingList(pRawContent->pWindowClasses);
  895. pRawContent->pWindowClasses = NULL;
  896. }
  897. RtlDestroyGrowingList(&pRawContent->FileMembers);
  898. RtlDestroyGrowingList(&pRawContent->AssemblyIdentityAttributes);
  899. return STATUS_SUCCESS;
  900. }
  901. NTSTATUS
  902. RtlpAllocateAndExtractString(
  903. PXML_EXTENT pXmlExtent,
  904. PUNICODE_STRING pusTargetString,
  905. PXML_RAWTOKENIZATION_STATE pState,
  906. PMINI_BUFFER pTargetBuffer
  907. )
  908. {
  909. NTSTATUS status = STATUS_SUCCESS;
  910. MINI_BUFFER mb;
  911. if (!ARGUMENT_PRESENT(pXmlExtent) || !ARGUMENT_PRESENT(pusTargetString) ||
  912. !ARGUMENT_PRESENT(pState) || !ARGUMENT_PRESENT(pTargetBuffer))
  913. {
  914. return STATUS_INVALID_PARAMETER;
  915. }
  916. RtlZeroMemory(pusTargetString, sizeof(*pusTargetString));
  917. mb = *pTargetBuffer;
  918. //
  919. // ISSUE:jonwis-2002-04-19: We need to clamp this max length elsewhere - we should not
  920. // be allowing arbitrarily-large attributes and whatnot. Unfortunately, this exposes
  921. // "implementation details", so this clamp should be on our side of the wall, /not/
  922. // in the XML parser itself.
  923. //
  924. pusTargetString->Length = 0;
  925. pusTargetString->MaximumLength = (USHORT)pXmlExtent->ulCharacters * sizeof(WCHAR);
  926. status = RtlMiniBufferAllocateBytes(&mb, pusTargetString->MaximumLength, &pusTargetString->Buffer);
  927. if (!NT_SUCCESS(status)) {
  928. return status;
  929. }
  930. status = RtlXmlExtentToString(pState, pXmlExtent, pusTargetString, NULL);
  931. if (!NT_SUCCESS(status)) {
  932. return status;
  933. }
  934. *pTargetBuffer = mb;
  935. return STATUS_SUCCESS;
  936. }
  937. NTSTATUS
  938. RtlpAllocateAndExtractString2(
  939. PXML_EXTENT pXmlExtent,
  940. PUNICODE_STRING *ppusTargetString,
  941. PXML_RAWTOKENIZATION_STATE pState,
  942. PMINI_BUFFER pTargetBuffer
  943. )
  944. {
  945. NTSTATUS status = STATUS_SUCCESS;
  946. MINI_BUFFER mb;
  947. if (!ARGUMENT_PRESENT(pXmlExtent) || !ARGUMENT_PRESENT(ppusTargetString) ||
  948. !ARGUMENT_PRESENT(pState) || !ARGUMENT_PRESENT(pTargetBuffer))
  949. {
  950. return STATUS_INVALID_PARAMETER;
  951. }
  952. *ppusTargetString = NULL;
  953. mb = *pTargetBuffer;
  954. status = RtlMiniBufferAllocate(&mb, UNICODE_STRING, ppusTargetString);
  955. if (!NT_SUCCESS(status)) {
  956. return status;
  957. }
  958. status = RtlpAllocateAndExtractString(
  959. pXmlExtent,
  960. *ppusTargetString,
  961. pState,
  962. pTargetBuffer);
  963. return status;
  964. }
  965. //
  966. // These help keep things aligned
  967. //
  968. #define ALIGN_SIZE(type) ROUND_UP_COUNT(sizeof(type))
  969. NTSTATUS
  970. RtlpCalculateCookedManifestContentSize(
  971. PRTL_MANIFEST_CONTENT_RAW pRawContent,
  972. PXML_RAWTOKENIZATION_STATE pState,
  973. PSIZE_T pcbRequired
  974. )
  975. {
  976. NTSTATUS status = STATUS_SUCCESS;
  977. SIZE_T cbRequired;
  978. ULONG ul = 0;
  979. ULONG ulNamespacesFound = 0;
  980. if (ARGUMENT_PRESENT(pcbRequired)) {
  981. *pcbRequired = 0;
  982. }
  983. if (!ARGUMENT_PRESENT(pRawContent) || !ARGUMENT_PRESENT(pState) || !ARGUMENT_PRESENT(pcbRequired)) {
  984. return STATUS_INVALID_PARAMETER;
  985. }
  986. cbRequired = ROUND_UP_COUNT(sizeof(MANIFEST_COOKED_DATA), ALIGNMENT_VALUE);
  987. //
  988. // For each file, gather up the data in the raw object.
  989. //
  990. cbRequired += ROUND_UP_COUNT(sizeof(MANIFEST_COOKED_FILE) * pRawContent->ulFileMembers, ALIGNMENT_VALUE);
  991. for (ul = 0; ul < pRawContent->ulFileMembers; ul++) {
  992. PASSEMBLY_MEMBER_FILE_RAW pRawFile = NULL;
  993. status = RtlIndexIntoGrowingList(&pRawContent->FileMembers, ul, (PVOID*)&pRawFile, FALSE);
  994. if (!NT_SUCCESS(status)) {
  995. goto Exit;
  996. }
  997. if (pRawFile->FileName.pvData != NULL) {
  998. cbRequired += ROUND_UP_COUNT(pRawFile->FileName.ulCharacters * sizeof(WCHAR), ALIGNMENT_VALUE);
  999. }
  1000. if (pRawFile->LoadFrom.pvData != NULL) {
  1001. cbRequired += ROUND_UP_COUNT(pRawFile->LoadFrom.ulCharacters * sizeof(WCHAR), ALIGNMENT_VALUE);
  1002. }
  1003. //
  1004. // Each two characters in the hash value string represents one byte.
  1005. //
  1006. if (pRawFile->HashValue.pvData != NULL) {
  1007. cbRequired += ROUND_UP_COUNT(pRawFile->HashValue.ulCharacters / 2, ALIGNMENT_VALUE);
  1008. }
  1009. }
  1010. //
  1011. // For now, we're none too bright about pooling namespaces on identity values. Luckily,
  1012. // values in different namespaces are now not the norm, so life gets easier.
  1013. //
  1014. cbRequired += ROUND_UP_COUNT(sizeof(MANIFEST_IDENTITY_TABLE), ALIGNMENT_VALUE);
  1015. cbRequired += ROUND_UP_COUNT(sizeof(MANIFEST_COOKED_IDENTITY) * pRawContent->ulAssemblyIdentitiesFound, ALIGNMENT_VALUE);
  1016. cbRequired += ROUND_UP_COUNT(sizeof(MANIFEST_COOKED_IDENTITY_PAIR) * pRawContent->ulAssemblyIdentityAttributes, ALIGNMENT_VALUE);
  1017. for (ul = 0; ul < pRawContent->ulAssemblyIdentityAttributes; ul++) {
  1018. PASSEMBLY_IDENTITY_ATTRIBUTE_RAW pRawAttribute = NULL;
  1019. ULONG ul2 = 0;
  1020. status = RtlIndexIntoGrowingList(&pRawContent->AssemblyIdentityAttributes, ul, (PVOID*)&pRawAttribute, FALSE);
  1021. if (!NT_SUCCESS(status)) {
  1022. goto Exit;
  1023. }
  1024. //
  1025. // We need this much extra space to to store the data
  1026. //
  1027. cbRequired += ROUND_UP_COUNT(pRawAttribute->Attribute.ulCharacters * sizeof(WCHAR), ALIGNMENT_VALUE);
  1028. cbRequired += ROUND_UP_COUNT(pRawAttribute->Value.ulCharacters * sizeof(WCHAR), ALIGNMENT_VALUE);
  1029. cbRequired += ROUND_UP_COUNT(pRawAttribute->Namespace.ulCharacters * sizeof(WCHAR), ALIGNMENT_VALUE);
  1030. }
  1031. *pcbRequired = cbRequired;
  1032. status = STATUS_SUCCESS;
  1033. Exit:
  1034. return status;
  1035. }
  1036. NTSTATUS FORCEINLINE
  1037. pExpandBuffer(
  1038. PUNICODE_STRING strTarget,
  1039. PVOID pvBaseBuffer,
  1040. SIZE_T cchCount
  1041. )
  1042. {
  1043. NTSTATUS status;
  1044. const USHORT usRequiredCb = (USHORT)(cchCount * sizeof(WCHAR));
  1045. if (strTarget->MaximumLength >= usRequiredCb) {
  1046. return STATUS_SUCCESS;
  1047. }
  1048. else {
  1049. if ((strTarget->Buffer != pvBaseBuffer) && (strTarget->Buffer != NULL)) {
  1050. if (!NT_SUCCESS(status = g_DefaultAllocator.pfnFree(strTarget->Buffer, NULL)))
  1051. return status;
  1052. }
  1053. if (!NT_SUCCESS(status = g_DefaultAllocator.pfnAlloc(usRequiredCb, (PVOID*)&strTarget->Buffer, NULL))) {
  1054. strTarget->Buffer = NULL;
  1055. strTarget->MaximumLength = strTarget->Length = 0;
  1056. return status;
  1057. }
  1058. strTarget->MaximumLength = usRequiredCb;
  1059. strTarget->Length = 0;
  1060. return STATUS_SUCCESS;
  1061. }
  1062. }
  1063. #define pFreeBuffer(buff, pvBase) do { \
  1064. if (((buff)->Buffer != pvBase) && ((buff)->Buffer != NULL)) { \
  1065. RtlDefaultFreer((buff)->Buffer, NULL); \
  1066. (buff)->Buffer = NULL; (buff)->MaximumLength = 0; } \
  1067. } while (0)
  1068. struct {
  1069. const UNICODE_STRING Text;
  1070. DigestType DigestValue;
  1071. } g_rgsHashDigests[] = {
  1072. { RTL_CONSTANT_STRING(L"fullfile"), DigestType_FullFile }
  1073. };
  1074. struct {
  1075. const UNICODE_STRING Text;
  1076. HashType HashAlgValue;
  1077. } g_rgsHashAlgs[] = {
  1078. { RTL_CONSTANT_STRING(L"sha1"), HashType_Sha1 },
  1079. { RTL_CONSTANT_STRING(L"sha"), HashType_Sha1 },
  1080. { RTL_CONSTANT_STRING(L"sha-256"), HashType_Sha256 },
  1081. { RTL_CONSTANT_STRING(L"sha-384"), HashType_Sha384 },
  1082. { RTL_CONSTANT_STRING(L"sha-512"), HashType_Sha512 },
  1083. { RTL_CONSTANT_STRING(L"md5"), HashType_MD5 },
  1084. { RTL_CONSTANT_STRING(L"md4"), HashType_MD4 },
  1085. { RTL_CONSTANT_STRING(L"md2"), HashType_MD4 },
  1086. };
  1087. NTSTATUS
  1088. RtlpParseDigestMethod(
  1089. PUNICODE_STRING pText,
  1090. DigestType *pDigestType
  1091. )
  1092. {
  1093. ULONG ul;
  1094. if (pDigestType != NULL)
  1095. *pDigestType = 0;
  1096. if (!ARGUMENT_PRESENT(pDigestType) || !ARGUMENT_PRESENT(pText)) {
  1097. return STATUS_INVALID_PARAMETER;
  1098. }
  1099. for (ul = 0; ul < NUMBER_OF(g_rgsHashDigests); ul++) {
  1100. if (RtlCompareUnicodeString(pText, &g_rgsHashDigests[ul].Text, TRUE) == 0) {
  1101. *pDigestType = g_rgsHashDigests[ul].DigestValue;
  1102. return STATUS_SUCCESS;
  1103. }
  1104. }
  1105. return STATUS_NOT_FOUND;
  1106. }
  1107. NTSTATUS
  1108. RtlpParseHashAlg(
  1109. PUNICODE_STRING pText,
  1110. HashType *pHashType
  1111. )
  1112. {
  1113. ULONG ul;
  1114. if (pHashType != NULL)
  1115. *pHashType = 0;
  1116. if (!ARGUMENT_PRESENT(pHashType) || !ARGUMENT_PRESENT(pText)) {
  1117. return STATUS_INVALID_PARAMETER;
  1118. }
  1119. for (ul = 0; ul < NUMBER_OF(g_rgsHashAlgs); ul++) {
  1120. if (RtlCompareUnicodeString(pText, &g_rgsHashAlgs[ul].Text, TRUE) == 0) {
  1121. *pHashType = g_rgsHashAlgs[ul].HashAlgValue;
  1122. return STATUS_SUCCESS;
  1123. }
  1124. }
  1125. return STATUS_NOT_FOUND;
  1126. }
  1127. NTSTATUS
  1128. RtlpAddRawIdentitiesToCookedContent(
  1129. PRTL_MANIFEST_CONTENT_RAW pRawContent,
  1130. PMANIFEST_COOKED_DATA pCookedContent,
  1131. PXML_RAWTOKENIZATION_STATE pState,
  1132. PMINI_BUFFER TargetBuffer
  1133. )
  1134. {
  1135. NTSTATUS status = STATUS_SUCCESS;
  1136. ULONG ul = 0;
  1137. PMANIFEST_IDENTITY_TABLE IdentityTable = NULL;
  1138. PMANIFEST_COOKED_IDENTITY IdentityList = NULL;
  1139. PMANIFEST_COOKED_IDENTITY_PAIR NameValueList = NULL;
  1140. //
  1141. // Start off by allocating space for the table of identities, and the
  1142. // table of individual identities
  1143. //
  1144. status = RtlMiniBufferAllocate(TargetBuffer, MANIFEST_IDENTITY_TABLE, &IdentityTable);
  1145. if (!NT_SUCCESS(status)) {
  1146. goto Exit;
  1147. }
  1148. status = RtlMiniBufferAllocateCount(TargetBuffer, MANIFEST_COOKED_IDENTITY, pRawContent->ulAssemblyIdentitiesFound, &IdentityList);
  1149. if (!NT_SUCCESS(status)) {
  1150. goto Exit;
  1151. }
  1152. RtlZeroMemory(IdentityList, sizeof(*IdentityList) * pRawContent->ulAssemblyIdentitiesFound);
  1153. IdentityTable->ulIdentityCount = pRawContent->ulAssemblyIdentitiesFound;
  1154. IdentityTable->ulRootIdentityIndex = ULONG_MAX;
  1155. IdentityTable->CookedIdentities = IdentityList;
  1156. //
  1157. // Now allocate the right number of identity components
  1158. //
  1159. status = RtlMiniBufferAllocateCount(TargetBuffer, MANIFEST_COOKED_IDENTITY_PAIR, pRawContent->ulAssemblyIdentityAttributes, &NameValueList);
  1160. if (!NT_SUCCESS(status)) {
  1161. goto Exit;
  1162. }
  1163. RtlZeroMemory(NameValueList, sizeof(*NameValueList) * pRawContent->ulAssemblyIdentityAttributes);
  1164. //
  1165. // Spiffy - now, we start adding identity components into the list. We'll assert that the
  1166. // array of components' indexes increases monotomically.
  1167. //
  1168. for (ul = 0; ul < pRawContent->ulAssemblyIdentityAttributes; ul++) {
  1169. PASSEMBLY_IDENTITY_ATTRIBUTE_RAW RawValue = NULL;
  1170. PMANIFEST_COOKED_IDENTITY pThisIdentity = IdentityList + ul;
  1171. status = RtlIndexIntoGrowingList(
  1172. &pRawContent->AssemblyIdentityAttributes,
  1173. ul,
  1174. (PVOID*)&RawValue,
  1175. FALSE);
  1176. if (!NT_SUCCESS(status))
  1177. goto Exit;
  1178. ASSERT(RawValue->ulIdentityIndex < pRawContent->ulAssemblyIdentitiesFound);
  1179. pThisIdentity = IdentityList + RawValue->ulIdentityIndex;
  1180. //
  1181. // If this is unset to start, then set it
  1182. //
  1183. if (pThisIdentity->pIdentityPairs == NULL) {
  1184. pThisIdentity->pIdentityPairs = NameValueList + ul;
  1185. }
  1186. //
  1187. // Allocate enough space to hold the namespace, name, etc.
  1188. //
  1189. if (RawValue->Namespace.pvData) {
  1190. status = RtlpAllocateAndExtractString(
  1191. &RawValue->Namespace,
  1192. &NameValueList[ul].Namespace,
  1193. pState,
  1194. TargetBuffer);
  1195. if (!NT_SUCCESS(status))
  1196. goto Exit;
  1197. }
  1198. status = RtlpAllocateAndExtractString(
  1199. &RawValue->Attribute,
  1200. &NameValueList[ul].Name,
  1201. pState,
  1202. TargetBuffer);
  1203. if (!NT_SUCCESS(status))
  1204. goto Exit;
  1205. status = RtlpAllocateAndExtractString(
  1206. &RawValue->Value,
  1207. &NameValueList[ul].Value,
  1208. pState,
  1209. TargetBuffer);
  1210. if (!NT_SUCCESS(status))
  1211. goto Exit;
  1212. pThisIdentity->ulIdentityComponents++;
  1213. }
  1214. pCookedContent->pManifestIdentity = IdentityTable;
  1215. pCookedContent->ulFlags |= COOKEDMANIFEST_HAS_IDENTITIES;
  1216. Exit:
  1217. return status;
  1218. }
  1219. NTSTATUS
  1220. RtlpAddRawFilesToCookedContent(
  1221. PRTL_MANIFEST_CONTENT_RAW pRawContent,
  1222. PMANIFEST_COOKED_DATA pCookedContent,
  1223. PXML_RAWTOKENIZATION_STATE pState,
  1224. PMINI_BUFFER TargetBuffer
  1225. )
  1226. {
  1227. NTSTATUS status = STATUS_SUCCESS;
  1228. ULONG ul;
  1229. MINI_BUFFER OurMiniBuffer;
  1230. RTL_UNICODE_STRING_BUFFER TempStringBuffer;
  1231. UCHAR TempStringBufferStatic[64];
  1232. if (!ARGUMENT_PRESENT(pRawContent) || !ARGUMENT_PRESENT(pState) || !ARGUMENT_PRESENT(TargetBuffer)) {
  1233. return STATUS_INVALID_PARAMETER;
  1234. }
  1235. RtlInitUnicodeStringBuffer(&TempStringBuffer, TempStringBufferStatic, sizeof(TempStringBufferStatic));
  1236. //
  1237. // Copy buffer state - if we succeed, we'll write the updated buffer back
  1238. // into the one that's tracking stuff in the caller.
  1239. //
  1240. OurMiniBuffer = *TargetBuffer;
  1241. pCookedContent->ulFileCount = pRawContent->ulFileMembers;
  1242. if (pRawContent->ulFileMembers == 0) {
  1243. pCookedContent->pCookedFiles = NULL;
  1244. }
  1245. else {
  1246. PASSEMBLY_MEMBER_FILE_RAW pRawFile = NULL;
  1247. status = RtlMiniBufferAllocateCount(
  1248. &OurMiniBuffer,
  1249. MANIFEST_COOKED_FILE,
  1250. pCookedContent->ulFileCount,
  1251. &pCookedContent->pCookedFiles);
  1252. if (!NT_SUCCESS(status)) {
  1253. return status;
  1254. }
  1255. //
  1256. // Now for each one, allocate the necessary UNICODE_STRINGs
  1257. //
  1258. for (ul = 0; ul < pRawContent->ulFileMembers; ul++) {
  1259. PMANIFEST_COOKED_FILE pFile = pCookedContent->pCookedFiles + ul;
  1260. pFile->ulFlags = 0;
  1261. status = RtlIndexIntoGrowingList(&pRawContent->FileMembers, ul, (PVOID*)&pRawFile, FALSE);
  1262. if (!NT_SUCCESS(status)) {
  1263. return status;
  1264. }
  1265. //
  1266. // If this fails, stop trying
  1267. //
  1268. if (pRawFile->FileName.pvData != NULL) {
  1269. status = RtlpAllocateAndExtractString(
  1270. &pRawFile->FileName,
  1271. &pFile->FileName,
  1272. pState,
  1273. &OurMiniBuffer);
  1274. if (!NT_SUCCESS(status))
  1275. goto Exit;
  1276. pFile->ulFlags |= COOKEDFILE_NAME_VALID;
  1277. }
  1278. if (pRawFile->LoadFrom.pvData != NULL) {
  1279. status = RtlpAllocateAndExtractString(
  1280. &pRawFile->LoadFrom,
  1281. &pFile->LoadFrom,
  1282. pState,
  1283. &OurMiniBuffer);
  1284. if (!NT_SUCCESS(status))
  1285. goto Exit;
  1286. pFile->ulFlags |= COOKEDFILE_LOADFROM_VALID;
  1287. }
  1288. //
  1289. // Get the digest method. We don't store this anywhere, but we need to get it out
  1290. // into a UNICODE_STRING for our parsing purposes
  1291. //
  1292. if (pRawFile->DigestMethod.pvData != NULL) {
  1293. status = RtlEnsureUnicodeStringBufferSizeBytes(
  1294. &TempStringBuffer,
  1295. pRawFile->DigestMethod.ulCharacters * sizeof(WCHAR)
  1296. );
  1297. if (!NT_SUCCESS(status))
  1298. goto Exit;
  1299. status = RtlXmlExtentToString(pState, &pRawFile->DigestMethod, &TempStringBuffer.String, NULL);
  1300. if (!NT_SUCCESS(status)) {
  1301. goto Exit;
  1302. }
  1303. status = RtlpParseDigestMethod(&TempStringBuffer.String, &pFile->usDigestAlgorithm);
  1304. if (!NT_SUCCESS(status)) {
  1305. goto Exit;
  1306. }
  1307. pFile->ulFlags |= COOKEDFILE_DIGEST_ALG_VALID;
  1308. }
  1309. if (pRawFile->HashAlg.pvData != NULL) {
  1310. status = RtlEnsureUnicodeStringBufferSizeChars(
  1311. &TempStringBuffer,
  1312. pRawFile->HashAlg.ulCharacters
  1313. );
  1314. if (!NT_SUCCESS(status))
  1315. goto Exit;
  1316. status = RtlXmlExtentToString(pState, &pRawFile->HashAlg, &TempStringBuffer.String, NULL);
  1317. if (!NT_SUCCESS(status)) {
  1318. goto Exit;
  1319. }
  1320. status = RtlpParseHashAlg(&TempStringBuffer.String, &pFile->usHashAlgorithm);
  1321. if (!NT_SUCCESS(status)) {
  1322. goto Exit;
  1323. }
  1324. pFile->ulFlags |= COOKEDFILE_HASH_ALG_VALID;
  1325. }
  1326. //
  1327. // Special case here - we should extract the hash string, and then turn it into
  1328. // bytes.
  1329. //
  1330. if (pRawFile->HashValue.pvData != NULL) {
  1331. status = RtlEnsureUnicodeStringBufferSizeChars(
  1332. &TempStringBuffer,
  1333. pRawFile->HashValue.ulCharacters);
  1334. if (!NT_SUCCESS(status))
  1335. goto Exit;
  1336. status = RtlXmlExtentToString(pState, &pRawFile->HashValue, &TempStringBuffer.String, NULL);
  1337. if (!NT_SUCCESS(status))
  1338. goto Exit;
  1339. if ((pRawFile->HashValue.ulCharacters % sizeof(WCHAR)) != 0) {
  1340. status = STATUS_INVALID_PARAMETER;
  1341. goto Exit;
  1342. }
  1343. else {
  1344. // Two characters per byte, high/low nibble
  1345. pFile->ulHashByteCount = pRawFile->HashValue.ulCharacters / 2;
  1346. }
  1347. status = RtlMiniBufferAllocateBytes(
  1348. &OurMiniBuffer,
  1349. pFile->ulHashByteCount,
  1350. &pFile->bHashData);
  1351. if (!NT_SUCCESS(status)) {
  1352. goto Exit;
  1353. }
  1354. status = RtlpConvertHexStringToBytes(
  1355. &TempStringBuffer.String,
  1356. pFile->bHashData,
  1357. pFile->ulHashByteCount
  1358. );
  1359. if (!NT_SUCCESS(status)) {
  1360. goto Exit;
  1361. }
  1362. pFile->ulFlags |= COOKEDFILE_HASHDATA_VALID;
  1363. }
  1364. }
  1365. }
  1366. pCookedContent->ulFlags |= COOKEDMANIFEST_HAS_FILES;
  1367. *TargetBuffer = OurMiniBuffer;
  1368. status = STATUS_SUCCESS;
  1369. Exit:
  1370. RtlFreeUnicodeStringBuffer(&TempStringBuffer);
  1371. return STATUS_SUCCESS;
  1372. }
  1373. NTSTATUS
  1374. RtlConvertRawToCookedContent(
  1375. PRTL_MANIFEST_CONTENT_RAW pRawContent,
  1376. PXML_RAWTOKENIZATION_STATE pState,
  1377. PVOID pvOriginalRegion,
  1378. SIZE_T cbRegionSize,
  1379. PSIZE_T pcbRequired
  1380. )
  1381. {
  1382. PVOID pvCursor;
  1383. ULONG ul;
  1384. SIZE_T cbRemains = 0;
  1385. SIZE_T cbRequired = 0;
  1386. NTSTATUS status = STATUS_SUCCESS;
  1387. MINI_BUFFER OutputBuffer;
  1388. PMANIFEST_COOKED_DATA pCookedContent = NULL;
  1389. if (pcbRequired)
  1390. *pcbRequired = 0;
  1391. //
  1392. // Giving a NULL output buffer means you have zero bytes. Don't claim otherwise.
  1393. //
  1394. if (!pvOriginalRegion && (cbRegionSize != 0)) {
  1395. return STATUS_INVALID_PARAMETER;
  1396. }
  1397. //
  1398. // No output buffer, you have to let us tell you how much space you need.
  1399. //
  1400. else if ((pvOriginalRegion == NULL) && (pcbRequired == NULL)) {
  1401. return STATUS_INVALID_PARAMETER;
  1402. }
  1403. //
  1404. // See how much we really need. I'm thinking we could do this in a single pass,
  1405. // and we'll probably want to for perf reasons, but for now we calculate, and then
  1406. // copy data around.
  1407. //
  1408. status = RtlpCalculateCookedManifestContentSize(
  1409. pRawContent,
  1410. pState,
  1411. &cbRequired);
  1412. //
  1413. // Too big - write the output size into the required space and return.
  1414. //
  1415. if (cbRequired > cbRegionSize) {
  1416. if (pcbRequired) *pcbRequired = cbRequired;
  1417. return STATUS_BUFFER_TOO_SMALL;
  1418. }
  1419. //
  1420. // Now, let's start writing data into the blob!
  1421. //
  1422. RtlMiniBufferInit(&OutputBuffer, pvOriginalRegion, cbRegionSize);
  1423. status = RtlMiniBufferAllocate(&OutputBuffer, MANIFEST_COOKED_DATA, &pCookedContent);
  1424. if (!NT_SUCCESS(status)) {
  1425. return status;
  1426. }
  1427. pCookedContent->cbTotalSize = cbRequired;
  1428. pCookedContent->ulFlags = 0;
  1429. status = RtlpAddRawFilesToCookedContent(
  1430. pRawContent,
  1431. pCookedContent,
  1432. pState,
  1433. &OutputBuffer);
  1434. if (!NT_SUCCESS(status)) {
  1435. return status;
  1436. }
  1437. status = RtlpAddRawIdentitiesToCookedContent(
  1438. pRawContent,
  1439. pCookedContent,
  1440. pState,
  1441. &OutputBuffer);
  1442. if (!NT_SUCCESS(status)) {
  1443. return status;
  1444. }
  1445. return STATUS_SUCCESS;
  1446. }