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.

698 lines
17 KiB

  1. #include "nt.h"
  2. #include "ntdef.h"
  3. #include "ntrtl.h"
  4. #include "nturtl.h"
  5. #include "ntrtl.h"
  6. #include "ntosp.h"
  7. #include "stdio.h"
  8. #include "sxs-rtl.h"
  9. #include "fasterxml.h"
  10. #include "skiplist.h"
  11. #include "namespacemanager.h"
  12. #include "xmlstructure.h"
  13. #include "sxsid.h"
  14. #include "xmlassert.h"
  15. #include "manifestinspection.h"
  16. void
  17. RtlTraceNtSuccessFailure(
  18. PCSTR pcszStatement,
  19. NTSTATUS FailureCode,
  20. PCSTR pcszFileName,
  21. LONG LineNumber
  22. )
  23. {
  24. CHAR SmallBuffer[512];
  25. STRING s;
  26. s.Buffer = SmallBuffer;
  27. s.Length = s.MaximumLength = (USHORT)_snprintf(
  28. "%s(%d): NTSTATUS 0x%08lx from '%s'\n",
  29. NUMBER_OF(SmallBuffer),
  30. pcszFileName,
  31. LineNumber,
  32. FailureCode,
  33. pcszStatement);
  34. #if 0 // When we move to kernel mode, we should turn this on - for now, let's just use OutputDebugStringA
  35. DebugPrint(&s, 0, 0);
  36. #else
  37. printf(SmallBuffer);
  38. #endif
  39. }
  40. #undef NT_SUCCESS
  41. #define NT_SUCCESS(q) (((status = (q)) < 0) ? (RtlTraceNtSuccessFailure(#q, status, __FILE__, __LINE__), FALSE) : TRUE)
  42. NTSTATUS
  43. RtlpGenerateIdentityFromAttributes(
  44. IN PXML_TOKENIZATION_STATE pState,
  45. IN PXMLDOC_ATTRIBUTE pAttributeList,
  46. IN ULONG ulAttributes,
  47. IN OUT PUNICODE_STRING pusDiskName,
  48. IN OUT PUNICODE_STRING pusTextualIdentity
  49. )
  50. /*++
  51. Parameters:
  52. pState - State of xml tokenization/parsing that can be used to extract strings
  53. and other stuff from the attributes in pAttributeList
  54. pAttributeList - Array of pointers to PXMLDOC_ATTRIBUTE structures that
  55. represent the identity attributes
  56. ulAttributes - Number of attributes in pAttributeList
  57. pusDiskName - Pointer to a UNICODE_STRING whose MaxLength is enough to contain
  58. 104 wchars. On exit, pusDiskName->Buffer will contain the on-disk identity
  59. of this set of attributes, and pusDiskName->Length will be the length of
  60. said data. (Not null terminated!)
  61. pusTextualIdentity - Pointer to a UNICODE_STRING which will be filled out on
  62. exit with the 'textual identity' of this set of attributes.
  63. --*/
  64. {
  65. NTSTATUS status = STATUS_SUCCESS;
  66. ULONG ulHash = 0;
  67. return status;
  68. }
  69. NTSTATUS
  70. RtlGetSxsAssemblyRoot(
  71. ULONG ulFlags,
  72. PUNICODE_STRING pusTempPathname,
  73. PUSHORT pulRequiredChars
  74. )
  75. {
  76. static const UNICODE_STRING s_us_WinSxsRoot = RTL_CONSTANT_STRING(L"\\WinSxS\\");
  77. NTSTATUS status = STATUS_SUCCESS;
  78. UNICODE_STRING NtSystemRoot;
  79. USHORT usLength;
  80. //
  81. // If there was a buffer, zero out the length so a naive caller won't
  82. // accidentally use it.
  83. //
  84. if (pusTempPathname) {
  85. pusTempPathname->Length = 0;
  86. }
  87. RtlInitUnicodeString(&NtSystemRoot, USER_SHARED_DATA->NtSystemRoot);
  88. usLength = NtSystemRoot.Length + s_us_WinSxsRoot.Length;
  89. if (pulRequiredChars)
  90. *pulRequiredChars = usLength;
  91. // No buffer, or it's too small completely, then oops
  92. if (!pusTempPathname || (pusTempPathname->MaximumLength < usLength)) {
  93. status = STATUS_BUFFER_TOO_SMALL;
  94. }
  95. // Otherwise, start copying
  96. else {
  97. PWCHAR pwszCursor = pusTempPathname->Buffer;
  98. RtlCopyMemory(pwszCursor, NtSystemRoot.Buffer, NtSystemRoot.Length);
  99. RtlCopyMemory((PCHAR)pwszCursor + NtSystemRoot.Length, s_us_WinSxsRoot.Buffer, s_us_WinSxsRoot.Length);
  100. pusTempPathname->Length = usLength;
  101. }
  102. return status;
  103. }
  104. // Installtemp identifiers are a combination of the current system time in
  105. // a "nicely formatted" format, plus some 16-bit hex uniqueness value
  106. #define CHARS_IN_INSTALLTEMP_IDENT (NUMBER_OF("yyyymmddhhmmssllll.xxxx") - 1)
  107. NTSTATUS
  108. RtlpCreateWinSxsTempPath(
  109. ULONG ulFlags,
  110. PUNICODE_STRING pusTempPath,
  111. WCHAR wchStatic,
  112. USHORT uscchStatus
  113. )
  114. {
  115. NTSTATUS status = STATUS_SUCCESS;
  116. USHORT ulLength = 0;
  117. if ((pusTempPath == NULL) || (ulFlags != 0)) {
  118. return STATUS_INVALID_PARAMETER;
  119. }
  120. //
  121. // Get the length of the root path
  122. //
  123. status = RtlGetSxsAssemblyRoot(0, NULL, &ulLength);
  124. if (!NT_SUCCESS(status) && (status != STATUS_BUFFER_TOO_SMALL)) {
  125. return status;
  126. }
  127. ulLength += 1 + CHARS_IN_INSTALLTEMP_IDENT;
  128. //
  129. // Ensure there's space
  130. //
  131. if (ulLength >= pusTempPath->MaximumLength) {
  132. pusTempPath->MaximumLength = ulLength;
  133. return STATUS_BUFFER_TOO_SMALL;
  134. }
  135. //
  136. // Get it again.
  137. //
  138. status = RtlGetSxsAssemblyRoot(0, pusTempPath, &ulLength);
  139. return status;
  140. }
  141. NTSTATUS
  142. RtlpPrepareForAssemblyInstall(
  143. ULONG ulFlags,
  144. PUNICODE_STRING pusTempPathname
  145. )
  146. {
  147. NTSTATUS status = STATUS_SUCCESS;
  148. USHORT ulRequired = 0;
  149. // Find out how long the 'root' path is.
  150. status = RtlGetSxsAssemblyRoot(0, NULL, &ulRequired);
  151. // Now let's find out how long our id is going to be
  152. return status;
  153. }
  154. const static WCHAR s_rgchBase64Encoding[] = {
  155. L'A', L'B', L'C', L'D', L'E', L'F', L'G', L'H', L'I', L'J', L'K', // 11
  156. L'L', L'M', L'N', L'O', L'P', L'Q', L'R', L'S', L'T', L'U', L'V', // 22
  157. L'W', L'X', L'Y', L'Z', L'a', L'b', L'c', L'd', L'e', L'f', L'g', // 33
  158. L'h', L'i', L'j', L'k', L'l', L'm', L'n', L'o', L'p', L'q', L'r', // 44
  159. L's', L't', L'u', L'v', L'w', L'x', L'y', L'z', L'0', L'1', L'2', // 55
  160. L'3', L'4', L'5', L'6', L'7', L'8', L'9', L'+', L'/' // 64
  161. };
  162. NTSTATUS
  163. RtlBase64Encode(
  164. PVOID pvBuffer,
  165. SIZE_T cbBuffer,
  166. PWSTR pwszEncoded,
  167. PSIZE_T pcchEncoded
  168. )
  169. {
  170. SIZE_T cchRequiredEncodingSize;
  171. SIZE_T iInput, iOutput;
  172. //
  173. // Null input buffer, null output size pointer, and a nonzero
  174. // encoded size with a null output buffer are all invalid
  175. // parameters
  176. //
  177. if (!pvBuffer || !pcchEncoded || ((*pcchEncoded > 0) && !pwszEncoded)) {
  178. return STATUS_INVALID_PARAMETER;
  179. }
  180. //
  181. // Make sure the buffer is large enough
  182. //
  183. cchRequiredEncodingSize = ((cbBuffer + 2) / 3) * 4;
  184. if (*pcchEncoded < cchRequiredEncodingSize) {
  185. *pcchEncoded = cchRequiredEncodingSize;
  186. return STATUS_BUFFER_TOO_SMALL;
  187. }
  188. //
  189. // Convert the input buffer bytes through the encoding table and
  190. // out into the output buffer.
  191. //
  192. iInput = iOutput = 0;
  193. while (iInput < cbBuffer) {
  194. const UCHAR uc0 = ((PUCHAR)pvBuffer)[iInput++];
  195. const UCHAR uc1 = (iInput < cbBuffer) ? ((PUCHAR)pvBuffer)[iInput++] : 0;
  196. const UCHAR uc2 = (iInput < cbBuffer) ? ((PUCHAR)pvBuffer)[iInput++] : 0;
  197. pwszEncoded[iOutput++] = s_rgchBase64Encoding[uc0 >> 2];
  198. pwszEncoded[iOutput++] = s_rgchBase64Encoding[((uc0 << 4) & 0x30) | ((uc1 >> 4) & 0xf)];
  199. pwszEncoded[iOutput++] = s_rgchBase64Encoding[((uc1 << 2) & 0x3c) | ((uc2 >> 6) & 0x3)];
  200. pwszEncoded[iOutput++] = s_rgchBase64Encoding[uc2 & 0x3f];
  201. }
  202. //
  203. // Fill in leftover bytes at the end
  204. //
  205. switch(cbBuffer % 3) {
  206. case 0:
  207. break;
  208. //
  209. // One byte out of three, add padding and fall through
  210. //
  211. case 1:
  212. pwszEncoded[iOutput - 2] = L'=';
  213. //
  214. // Two bytes out of three, add padding.
  215. case 2:
  216. pwszEncoded[iOutput - 1] = L'=';
  217. break;
  218. }
  219. return STATUS_SUCCESS;
  220. }
  221. NTSTATUS
  222. RtlInstallAssembly(
  223. ULONG ulFlags,
  224. PCWSTR pcwszManifestPath
  225. )
  226. {
  227. SIZE_T cbFileSize;
  228. PVOID pvFileBase = 0;
  229. NTSTATUS status;
  230. PRTL_MANIFEST_CONTENT_RAW pRawContent = NULL;
  231. XML_TOKENIZATION_STATE TokenizationStateUsed;
  232. UNICODE_STRING usFilePath;
  233. status = RtlSxsInitializeManifestRawContent(RTLIMS_GATHER_FILES, &pRawContent, NULL, 0);
  234. if (!NT_SUCCESS(status)) {
  235. goto Exit;
  236. }
  237. //
  238. // Get ahold of the file
  239. //
  240. status = RtlOpenAndMapEntireFile(pcwszManifestPath, &pvFileBase, &cbFileSize);
  241. if (!NT_SUCCESS(status)) {
  242. goto Exit;
  243. }
  244. //
  245. // We should have found some files
  246. //
  247. status = RtlInspectManifestStream(
  248. RTLIMS_GATHER_FILES,
  249. pvFileBase,
  250. cbFileSize,
  251. pRawContent,
  252. &TokenizationStateUsed);
  253. if (!NT_SUCCESS(status))
  254. goto Exit;
  255. //
  256. // Validate that the assembly
  257. Exit:
  258. if (pRawContent) {
  259. RtlSxsDestroyManifestContent(pRawContent);
  260. }
  261. RtlUnmapViewOfFile(pvFileBase);
  262. return status;
  263. }
  264. BOOLEAN
  265. RtlDosPathNameToNtPathName_Ustr(
  266. IN PCUNICODE_STRING DosFileNameString,
  267. OUT PUNICODE_STRING NtFileName,
  268. OUT PWSTR *FilePart OPTIONAL,
  269. OUT PRTL_RELATIVE_NAME_U RelativeName OPTIONAL
  270. );
  271. NTSTATUS
  272. RtlOpenAndMapEntireFile(
  273. PCWSTR pcwszFilePath,
  274. PVOID *ppvMappedView,
  275. PSIZE_T pcbFileSize
  276. )
  277. {
  278. HANDLE SectionHandle = INVALID_HANDLE_VALUE;
  279. HANDLE FileHandle = INVALID_HANDLE_VALUE;
  280. UNICODE_STRING ObjectName;
  281. OBJECT_ATTRIBUTES ObjA;
  282. POBJECT_ATTRIBUTES pObjA;
  283. ACCESS_MASK DesiredAccess;
  284. ULONG ulAllocationAttributes;
  285. NTSTATUS status;
  286. IO_STATUS_BLOCK IOStatusBlock;
  287. BOOLEAN Translation;
  288. SIZE_T FileSize;
  289. FILE_STANDARD_INFORMATION Info;
  290. if (pcbFileSize) {
  291. *pcbFileSize = 0;
  292. }
  293. if (ppvMappedView) {
  294. *ppvMappedView = NULL;
  295. }
  296. if (!ARGUMENT_PRESENT(pcwszFilePath)) {
  297. return STATUS_INVALID_PARAMETER;
  298. }
  299. if (!ARGUMENT_PRESENT(pcbFileSize)) {
  300. return STATUS_INVALID_PARAMETER;
  301. }
  302. if (!ARGUMENT_PRESENT(ppvMappedView)) {
  303. return STATUS_INVALID_PARAMETER;
  304. }
  305. Translation = RtlDosPathNameToNtPathName_U(
  306. pcwszFilePath,
  307. &ObjectName,
  308. NULL,
  309. NULL);
  310. if (!Translation) {
  311. return STATUS_NOT_FOUND;
  312. }
  313. //
  314. // Open the file requested
  315. //
  316. InitializeObjectAttributes(
  317. &ObjA,
  318. &ObjectName,
  319. OBJ_CASE_INSENSITIVE,
  320. NULL,
  321. NULL);
  322. status = NtOpenFile(
  323. &FileHandle,
  324. FILE_GENERIC_READ,
  325. &ObjA,
  326. &IOStatusBlock,
  327. FILE_SHARE_READ | FILE_SHARE_DELETE,
  328. FILE_NON_DIRECTORY_FILE);
  329. if (!NT_SUCCESS(status)) {
  330. goto ErrorExit;
  331. }
  332. status = NtQueryInformationFile(
  333. FileHandle,
  334. &IOStatusBlock,
  335. &Info,
  336. sizeof(Info),
  337. FileStandardInformation);
  338. if (!NT_SUCCESS(status)) {
  339. goto ErrorExit;
  340. }
  341. *pcbFileSize = (SIZE_T)Info.EndOfFile.QuadPart;
  342. status = NtCreateSection(
  343. &SectionHandle,
  344. SECTION_MAP_READ | SECTION_QUERY,
  345. NULL,
  346. NULL,
  347. PAGE_READONLY,
  348. SEC_COMMIT,
  349. FileHandle);
  350. if (!NT_SUCCESS(status)) {
  351. goto ErrorExit;
  352. }
  353. //
  354. // Don't need the file object anymore, unmap it
  355. //
  356. status = NtClose(FileHandle);
  357. FileHandle = INVALID_HANDLE_VALUE;;
  358. *ppvMappedView = NULL;
  359. //
  360. // Map the whole file
  361. //
  362. status = NtMapViewOfSection(
  363. SectionHandle,
  364. NtCurrentProcess(),
  365. ppvMappedView,
  366. 0, // Zero bits
  367. 0, // Committed size
  368. NULL, // SectionOffset
  369. pcbFileSize, // Size of this file, in bytes
  370. ViewShare,
  371. 0,
  372. PAGE_READONLY);
  373. status = NtClose(SectionHandle);
  374. SectionHandle = INVALID_HANDLE_VALUE;
  375. //
  376. // Reset this - the NtMapViewOfSection allocates on page granularity
  377. //
  378. *pcbFileSize = (SIZE_T)Info.EndOfFile.QuadPart;
  379. Exit:
  380. return status;
  381. ErrorExit:
  382. if (FileHandle != INVALID_HANDLE_VALUE) {
  383. NtClose(FileHandle);
  384. FileHandle = INVALID_HANDLE_VALUE;
  385. }
  386. if (SectionHandle != INVALID_HANDLE_VALUE) {
  387. NtClose(SectionHandle);
  388. SectionHandle = INVALID_HANDLE_VALUE;
  389. }
  390. if (ppvMappedView && (*ppvMappedView != NULL)) {
  391. NTSTATUS newstatus = NtUnmapViewOfSection(NtCurrentProcess(), *ppvMappedView);
  392. //
  393. // Failed while failing
  394. //
  395. if (!NT_SUCCESS(newstatus)) {
  396. }
  397. *pcbFileSize = 0;
  398. }
  399. goto Exit;
  400. }
  401. NTSTATUS
  402. RtlUnmapViewOfFile(
  403. PVOID pvBase
  404. )
  405. {
  406. NTSTATUS status;
  407. status = NtUnmapViewOfSection(
  408. NtCurrentProcess(),
  409. pvBase);
  410. return status;
  411. }
  412. NTSTATUS FASTCALL
  413. RtlMiniHeapAlloc(
  414. SIZE_T cb,
  415. PVOID *ppvAllocated,
  416. PVOID pvContext
  417. )
  418. {
  419. PRTL_MINI_HEAP pContent = (PRTL_MINI_HEAP)pvContext;
  420. if ((pContent == NULL) || (ppvAllocated == NULL)) {
  421. return STATUS_INVALID_PARAMETER;
  422. }
  423. if (pContent->cbAvailableBytes < cb) {
  424. return g_DefaultAllocator.pfnAlloc(cb, ppvAllocated, NULL);
  425. }
  426. else {
  427. *ppvAllocated = pContent->pvNextAvailableByte;
  428. pContent->cbAvailableBytes -= cb;
  429. pContent->pvNextAvailableByte = (PUCHAR)pContent->pvNextAvailableByte + cb;
  430. return STATUS_SUCCESS;
  431. }
  432. }
  433. NTSTATUS FASTCALL
  434. RtlMiniHeapFree(
  435. PVOID pvAllocation,
  436. PVOID pvContext
  437. )
  438. {
  439. PRTL_MINI_HEAP pContent = (PRTL_MINI_HEAP)pvContext;
  440. if ((pvAllocation < pContent->pvAllocationBase) ||
  441. (pvAllocation >= (PVOID)((PUCHAR)pContent->pvAllocationBase + pContent->cbOriginalSize)))
  442. {
  443. return g_DefaultAllocator.pfnFree(pvAllocation, NULL);
  444. }
  445. else {
  446. return STATUS_SUCCESS;
  447. }
  448. }
  449. NTSTATUS FASTCALL
  450. RtlInitializeMiniHeap(
  451. PRTL_MINI_HEAP MiniHeap,
  452. PVOID pvTargetRegion,
  453. SIZE_T cbRegionSize
  454. )
  455. {
  456. if (!MiniHeap || !(pvTargetRegion || (cbRegionSize == 0))) {
  457. return STATUS_INVALID_PARAMETER;
  458. }
  459. MiniHeap->pvNextAvailableByte = pvTargetRegion;
  460. MiniHeap->pvAllocationBase = pvTargetRegion;
  461. MiniHeap->cbAvailableBytes = cbRegionSize;
  462. MiniHeap->cbOriginalSize = cbRegionSize;
  463. return STATUS_SUCCESS;
  464. }
  465. NTSTATUS FASTCALL
  466. RtlInitializeMiniHeapInPlace(
  467. PVOID pvRegion,
  468. SIZE_T cbOriginalSize,
  469. PRTL_MINI_HEAP *ppMiniHeap
  470. )
  471. {
  472. PRTL_MINI_HEAP pMiniHeapTemp = NULL;
  473. if (!ppMiniHeap)
  474. return STATUS_INVALID_PARAMETER;
  475. *ppMiniHeap = NULL;
  476. if (!(pvRegion || (cbOriginalSize == 0))) {
  477. return STATUS_INVALID_PARAMETER;
  478. }
  479. if (cbOriginalSize < sizeof(RTL_MINI_HEAP)) {
  480. return STATUS_NO_MEMORY;
  481. }
  482. pMiniHeapTemp = (PRTL_MINI_HEAP)pvRegion;
  483. pMiniHeapTemp->cbAvailableBytes = cbOriginalSize - sizeof(RTL_MINI_HEAP);
  484. pMiniHeapTemp->cbOriginalSize = pMiniHeapTemp->cbAvailableBytes;
  485. pMiniHeapTemp->pvAllocationBase = pMiniHeapTemp + 1;
  486. pMiniHeapTemp->pvNextAvailableByte = pMiniHeapTemp->pvAllocationBase;
  487. *ppMiniHeap = pMiniHeapTemp;
  488. return STATUS_SUCCESS;
  489. }
  490. NTSTATUS
  491. RtlpConvertHexStringToBytes(
  492. PUNICODE_STRING pSourceString,
  493. PBYTE pbTarget,
  494. SIZE_T cbTarget
  495. )
  496. {
  497. NTSTATUS status = STATUS_SUCCESS;
  498. PCWSTR pcSource = pSourceString->Buffer;
  499. ULONG ul = 0;
  500. if (cbTarget < (pSourceString->Length / (2 * sizeof(WCHAR)))) {
  501. return STATUS_BUFFER_TOO_SMALL;
  502. }
  503. else if ((pSourceString->Length % sizeof(WCHAR)) != 0) {
  504. return STATUS_INVALID_PARAMETER;
  505. }
  506. for (ul = 0; ul < (pSourceString->Length / sizeof(pSourceString->Buffer[0])); ul += 2) {
  507. BYTE bvLow, bvHigh;
  508. const WCHAR wchFirst = *pcSource++;
  509. const WCHAR wchSecond = *pcSource++;
  510. //
  511. // Set the high nibble
  512. //
  513. switch (wchFirst) {
  514. case L'0': case L'1': case L'2': case L'3':
  515. case L'4': case L'5': case L'6': case L'7':
  516. case L'8': case L'9':
  517. bvHigh = wchFirst - L'0';
  518. break;
  519. case L'a': case L'b': case L'c':
  520. case L'd': case L'e': case L'f':
  521. bvHigh = (wchFirst - L'a') + 0x10;
  522. break;
  523. case L'A': case L'B': case L'C':
  524. case L'D': case L'E': case L'F':
  525. bvHigh = (wchFirst - L'A') + 0x10;
  526. break;
  527. default:
  528. return STATUS_INVALID_PARAMETER;
  529. }
  530. //
  531. // Set the high nibble
  532. //
  533. switch (wchSecond) {
  534. case L'0': case L'1': case L'2': case L'3':
  535. case L'4': case L'5': case L'6': case L'7':
  536. case L'8': case L'9':
  537. bvLow = wchSecond - L'0';
  538. break;
  539. case L'a': case L'b': case L'c':
  540. case L'd': case L'e': case L'f':
  541. bvLow = (wchSecond - L'a') + 0x10;
  542. break;
  543. case L'A': case L'B': case L'C':
  544. case L'D': case L'E': case L'F':
  545. bvLow = (wchSecond - L'A') + 0x10;
  546. break;
  547. default:
  548. return STATUS_INVALID_PARAMETER;
  549. }
  550. pbTarget[ul / 2] = (bvHigh << 4) | bvLow;
  551. }
  552. return STATUS_SUCCESS;
  553. }