Source code of Windows XP (NT5)
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.

1051 lines
27 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. init.c
  5. Abstract:
  6. Utility routines for sac driver
  7. Author:
  8. Andrew Ritz (andrewr) - 15 June, 2000
  9. Revision History:
  10. --*/
  11. #include "sac.h"
  12. VOID
  13. AppendMessage(
  14. PWSTR OutPutBuffer,
  15. ULONG MessageId,
  16. PWSTR ValueBuffer OPTIONAL
  17. );
  18. NTSTATUS
  19. InsertRegistrySzIntoMachineInfoBuffer(
  20. PWSTR KeyName,
  21. PWSTR ValueName,
  22. ULONG MessageId
  23. );
  24. #ifdef ALLOC_PRAGMA
  25. #pragma alloc_text( INIT, PreloadGlobalMessageTable )
  26. #pragma alloc_text( INIT, AppendMessage )
  27. #pragma alloc_text( INIT, InsertRegistrySzIntoMachineInfoBuffer )
  28. #pragma alloc_text( INIT, InitializeMachineInformation )
  29. #endif
  30. //
  31. // Message Table routines. We load all of our message table entries into a
  32. // global non-paged structure so that we can send text to HeadlessDispatch at
  33. // any time.
  34. //
  35. typedef struct _MESSAGE_TABLE_ENTRY {
  36. ULONG MessageId;
  37. PCWSTR MessageText;
  38. } MESSAGE_TABLE_ENTRY, *PMESSAGE_TABLE_ENTRY;
  39. PMESSAGE_TABLE_ENTRY GlobalMessageTable;
  40. ULONG GlobalMessageTableCount;
  41. PUCHAR Utf8ConversionBuffer;
  42. ULONG Utf8ConversionBufferSize = MEMORY_INCREMENT;
  43. #define MESSAGE_INITIAL 1
  44. #define MESSAGE_FINAL 200
  45. //
  46. // Machine Information table and routines.
  47. //
  48. #define INIT_OBJA(Obja,UnicodeString,UnicodeText) \
  49. \
  50. RtlInitUnicodeString((UnicodeString),(UnicodeText)); \
  51. \
  52. InitializeObjectAttributes( \
  53. (Obja), \
  54. (UnicodeString), \
  55. OBJ_CASE_INSENSITIVE, \
  56. NULL, \
  57. NULL \
  58. )
  59. extern char *GlobalBuffer;
  60. PWSTR MachineInformationBuffer = NULL;
  61. extern
  62. BOOLEAN
  63. ExVerifySuite(
  64. SUITE_TYPE SuiteType
  65. );
  66. VOID
  67. SacFormatMessage(
  68. PWSTR OutputString,
  69. PWSTR InputString,
  70. ULONG InputStringLength
  71. )
  72. /*++
  73. Routine Description:
  74. This routine parses the InputString for any control characters in the
  75. message, then converts those control characters.
  76. Arguments:
  77. OutputString - holds formatted string.
  78. InputString - original unformatted string.
  79. InputStringLength - length of unformatted string.
  80. Return Value:
  81. NONE
  82. --*/
  83. {
  84. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  85. KdPrint(("SAC SacFormatMessage: Entering.\n")));
  86. if( (InputString == NULL) ||
  87. (OutputString == NULL) ||
  88. (InputStringLength == 0) ) {
  89. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  90. KdPrint(("SAC SacFormatMessage: Exiting with invalid parameters.\n")));
  91. return;
  92. }
  93. while( (*InputString != L'\0') &&
  94. (InputStringLength) ) {
  95. if( *InputString == L'%' ) {
  96. //
  97. // Possibly a control sequence.
  98. //
  99. if( *(InputString+1) == L'0' ) {
  100. *OutputString = L'\0';
  101. OutputString++;
  102. goto SacFormatMessage_Done;
  103. } else if( *(InputString+1) == L'%' ) {
  104. *OutputString = L'%';
  105. OutputString++;
  106. InputString += 2;
  107. } else if( *(InputString+1) == L'\\' ) {
  108. *OutputString = L'\r';
  109. OutputString++;
  110. *OutputString = L'\n';
  111. OutputString++;
  112. InputString += 2;
  113. } else if( *(InputString+1) == L'r' ) {
  114. *OutputString = L'\r';
  115. InputString += 2;
  116. OutputString++;
  117. } else if( *(InputString+1) == L'b' ) {
  118. *OutputString = L' ';
  119. InputString += 2;
  120. OutputString++;
  121. } else if( *(InputString+1) == L'.' ) {
  122. *OutputString = L'.';
  123. InputString += 2;
  124. OutputString++;
  125. } else if( *(InputString+1) == L'!' ) {
  126. *OutputString = L'!';
  127. InputString += 2;
  128. OutputString++;
  129. } else {
  130. //
  131. // Don't know what this is. eat the '%' character.
  132. //
  133. InputString += 1;
  134. }
  135. } else {
  136. *OutputString++ = *InputString++;
  137. }
  138. InputStringLength--;
  139. }
  140. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  141. KdPrint(("SAC SacFormatMessage: Exiting.\n")));
  142. SacFormatMessage_Done:
  143. return;
  144. }
  145. NTSTATUS
  146. PreloadGlobalMessageTable(
  147. PVOID ImageBase
  148. )
  149. /*++
  150. Routine Description:
  151. This routine loads all of our message table entries into a global
  152. structure and
  153. Arguments:
  154. ImageBase - pointer to image base for locating resources
  155. Return Value:
  156. NTSTATUS code indicating outcome.
  157. --*/
  158. {
  159. ULONG Count,EntryCount;
  160. SIZE_T TotalSizeInBytes = 0;
  161. NTSTATUS Status;
  162. PMESSAGE_RESOURCE_ENTRY messageEntry;
  163. PWSTR pStringBuffer;
  164. PAGED_CODE( );
  165. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC PreloadGlobalMessageTable: Entering.\n")));
  166. //
  167. // if it already exists, then just return success
  168. //
  169. if (GlobalMessageTable != NULL) {
  170. Status = STATUS_SUCCESS;
  171. goto exit;
  172. }
  173. ASSERT( MESSAGE_FINAL > MESSAGE_INITIAL );
  174. //
  175. // get the total required size for the table.
  176. //
  177. for (Count = MESSAGE_INITIAL; Count != MESSAGE_FINAL ; Count++) {
  178. Status = RtlFindMessage(ImageBase,
  179. 11, // RT_MESSAGETABLE
  180. LANG_NEUTRAL,
  181. Count,
  182. &messageEntry
  183. );
  184. if (NT_SUCCESS(Status)) {
  185. //
  186. // add it on to our total size.
  187. //
  188. // the messageEntry size contains the structure size + the size of the text.
  189. //
  190. ASSERT(messageEntry->Flags & MESSAGE_RESOURCE_UNICODE);
  191. TotalSizeInBytes += sizeof(MESSAGE_TABLE_ENTRY) +
  192. (messageEntry->Length - FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY, Text));
  193. GlobalMessageTableCount +=1;
  194. }
  195. }
  196. if (TotalSizeInBytes == 0) {
  197. IF_SAC_DEBUG(
  198. SAC_DEBUG_FAILS,
  199. KdPrint(("SAC PreloadGlobalMessageTable: No Messages.\n")));
  200. Status = STATUS_INVALID_PARAMETER;
  201. goto exit;
  202. }
  203. //
  204. // Allocate space for the table.
  205. //
  206. GlobalMessageTable = (PMESSAGE_TABLE_ENTRY) ALLOCATE_POOL( TotalSizeInBytes, GENERAL_POOL_TAG);
  207. if (!GlobalMessageTable) {
  208. Status = STATUS_NO_MEMORY;
  209. goto exit;
  210. }
  211. //
  212. // go through again, this time filling out the table with actual data
  213. //
  214. pStringBuffer = (PWSTR)((ULONG_PTR)GlobalMessageTable +
  215. (ULONG_PTR)(sizeof(MESSAGE_TABLE_ENTRY)*GlobalMessageTableCount));
  216. EntryCount = 0;
  217. for (Count = MESSAGE_INITIAL ; Count != MESSAGE_FINAL ; Count++) {
  218. Status = RtlFindMessage(ImageBase,
  219. 11, // RT_MESSAGETABLE
  220. LANG_NEUTRAL,
  221. Count,
  222. &messageEntry
  223. );
  224. if (NT_SUCCESS(Status)) {
  225. ULONG TextSize = messageEntry->Length - FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY, Text);
  226. GlobalMessageTable[EntryCount].MessageId = Count;
  227. GlobalMessageTable[EntryCount].MessageText = pStringBuffer;
  228. //
  229. // Send the message through our Formatting filter as it passes
  230. // into our global message structure.
  231. //
  232. SacFormatMessage( pStringBuffer, (PWSTR)messageEntry->Text, TextSize );
  233. ASSERT( (wcslen(pStringBuffer)*sizeof(WCHAR)) <= TextSize );
  234. pStringBuffer = (PWSTR)((ULONG_PTR)pStringBuffer + (ULONG_PTR)(TextSize));
  235. EntryCount += 1;
  236. }
  237. }
  238. Status = STATUS_SUCCESS;
  239. exit:
  240. IF_SAC_DEBUG(
  241. SAC_DEBUG_FUNC_TRACE,
  242. KdPrint(("SAC PreloadGlobalMessageTable: Exiting with status 0x%0x.\n",
  243. Status)));
  244. return(Status);
  245. }
  246. NTSTATUS
  247. TearDownGlobalMessageTable(
  248. VOID
  249. )
  250. {
  251. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC PreloadGlobalMessageTable: Entering.\n")));
  252. if (GlobalMessageTable) {
  253. FREE_POOL( &GlobalMessageTable );
  254. }
  255. IF_SAC_DEBUG(
  256. SAC_DEBUG_FUNC_TRACE,
  257. KdPrint(("SAC TearDownGlobalMessageTable: Exiting\n")));
  258. return(STATUS_SUCCESS);
  259. }
  260. PCWSTR
  261. GetMessage(
  262. ULONG MessageId
  263. )
  264. {
  265. PMESSAGE_TABLE_ENTRY pMessageTable;
  266. ULONG Count;
  267. if (!GlobalMessageTable) {
  268. return(NULL);
  269. }
  270. for (Count = 0; Count < GlobalMessageTableCount; Count++) {
  271. pMessageTable = &GlobalMessageTable[Count];
  272. if (pMessageTable->MessageId == MessageId) {
  273. return(pMessageTable->MessageText);
  274. }
  275. }
  276. ASSERT( FALSE );
  277. return(NULL);
  278. }
  279. BOOLEAN
  280. SacTranslateUnicodeToUtf8(
  281. PCWSTR SourceBuffer,
  282. UCHAR *DestinationBuffer
  283. )
  284. {
  285. ULONG Count = 0;
  286. //
  287. // convert into UTF8 for actual transmission
  288. //
  289. // UTF-8 encodes 2-byte Unicode characters as follows:
  290. // If the first nine bits are zero (00000000 0xxxxxxx), encode it as one byte 0xxxxxxx
  291. // If the first five bits are zero (00000yyy yyxxxxxx), encode it as two bytes 110yyyyy 10xxxxxx
  292. // Otherwise (zzzzyyyy yyxxxxxx), encode it as three bytes 1110zzzz 10yyyyyy 10xxxxxx
  293. //
  294. DestinationBuffer[Count] = (UCHAR)'\0';
  295. while (*SourceBuffer) {
  296. if( (*SourceBuffer & 0xFF80) == 0 ) {
  297. //
  298. // if the top 9 bits are zero, then just
  299. // encode as 1 byte. (ASCII passes through unchanged).
  300. //
  301. DestinationBuffer[Count++] = (UCHAR)(*SourceBuffer & 0x7F);
  302. } else if( (*SourceBuffer & 0xF700) == 0 ) {
  303. //
  304. // if the top 5 bits are zero, then encode as 2 bytes
  305. //
  306. DestinationBuffer[Count++] = (UCHAR)((*SourceBuffer >> 6) & 0x1F) | 0xC0;
  307. DestinationBuffer[Count++] = (UCHAR)(*SourceBuffer & 0xBF) | 0x80;
  308. } else {
  309. //
  310. // encode as 3 bytes
  311. //
  312. DestinationBuffer[Count++] = (UCHAR)((*SourceBuffer >> 12) & 0xF) | 0xE0;
  313. DestinationBuffer[Count++] = (UCHAR)((*SourceBuffer >> 6) & 0x3F) | 0x80;
  314. DestinationBuffer[Count++] = (UCHAR)(*SourceBuffer & 0xBF) | 0x80;
  315. }
  316. SourceBuffer += 1;
  317. }
  318. DestinationBuffer[Count] = (UCHAR)'\0';
  319. return(TRUE);
  320. }
  321. BOOLEAN
  322. SacPutUnicodeString(
  323. PCWSTR String
  324. )
  325. {
  326. if (!Utf8ConversionBuffer) {
  327. return(FALSE);
  328. }
  329. ASSERT( (wcslen(String)+1)*sizeof(WCHAR) < Utf8ConversionBufferSize );
  330. SacTranslateUnicodeToUtf8(String,Utf8ConversionBuffer);
  331. SacPutString(Utf8ConversionBuffer);
  332. return(TRUE);
  333. }
  334. BOOLEAN
  335. SacPutSimpleMessage(
  336. ULONG MessageId
  337. )
  338. {
  339. PCWSTR p;
  340. p = GetMessage(MessageId);
  341. if (p) {
  342. SacPutUnicodeString(p);
  343. return(TRUE);
  344. }
  345. return(FALSE);
  346. }
  347. VOID
  348. SacPutString(
  349. PUCHAR String
  350. )
  351. /*++
  352. Routine Description:
  353. This routine takes a string and packages it into a command structure for the
  354. HeadlessDispatch routine.
  355. Arguments:
  356. String - The string to display.
  357. Return Value:
  358. None.
  359. --*/
  360. {
  361. SIZE_T Length;
  362. ASSERT(FIELD_OFFSET(HEADLESS_CMD_PUT_STRING, String) == 0); // ASSERT if anyone changes this structure.
  363. Length = strlen((LPSTR)String) + sizeof('\0');
  364. HeadlessDispatch(HeadlessCmdPutString,
  365. (PHEADLESS_CMD_PUT_STRING)String,
  366. Length,
  367. NULL,
  368. NULL
  369. );
  370. }
  371. VOID
  372. AppendMessage(
  373. PWSTR OutPutBuffer,
  374. ULONG MessageId,
  375. PWSTR ValueBuffer OPTIONAL
  376. )
  377. /*++
  378. Routine Description:
  379. This function will insert the valuestring into the specified message, then
  380. concatenate the resulting string onto the OutPutBuffer.
  381. Arguments:
  382. OutPutBuffer The resulting String.
  383. MessageId ID of the formatting message to use.
  384. ValueBUffer Value string to be inserted into the message.
  385. Return Value:
  386. NONE
  387. --*/
  388. {
  389. PWSTR MyTemporaryBuffer = NULL;
  390. PCWSTR p;
  391. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  392. KdPrint(("SAC AppendMessage: Entering.\n")));
  393. p = GetMessage(MessageId);
  394. if( p == NULL ) {
  395. return;
  396. }
  397. if( ValueBuffer == NULL ) {
  398. wcscat( OutPutBuffer, p );
  399. } else {
  400. MyTemporaryBuffer = (PWSTR)(wcschr(OutPutBuffer, L'\0'));
  401. if( MyTemporaryBuffer == NULL ) {
  402. MyTemporaryBuffer = OutPutBuffer;
  403. }
  404. swprintf( MyTemporaryBuffer, p, ValueBuffer );
  405. }
  406. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  407. KdPrint(("SAC AppendMessage: Entering.\n")));
  408. return;
  409. }
  410. NTSTATUS
  411. InsertRegistrySzIntoMachineInfoBuffer(
  412. PWSTR KeyName,
  413. PWSTR ValueName,
  414. ULONG MessageId
  415. )
  416. /*++
  417. Routine Description:
  418. This function will go query the registry and pull the specified Value.
  419. We will then insert this value into the specified message, then concatenate
  420. the resulting string into our MachineInformationBuffer.
  421. Arguments:
  422. KeyName Name of the registry key we'll be querying.
  423. ValueName Name of the registry value we'll be querying.
  424. MessageId ID of the formatting message to use.
  425. Return Value:
  426. NTSTATUS.
  427. --*/
  428. {
  429. NTSTATUS Status = STATUS_SUCCESS;
  430. ULONG KeyValueLength = 0;
  431. PKEY_VALUE_PARTIAL_INFORMATION ValueBuffer = NULL;
  432. OBJECT_ATTRIBUTES Obja;
  433. UNICODE_STRING UnicodeString;
  434. HANDLE KeyHandle;
  435. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  436. KdPrint(("SAC InsertRegistrySzIntoMachineInfoBuffer: Entering.\n")));
  437. INIT_OBJA( &Obja, &UnicodeString, KeyName );
  438. Status = ZwOpenKey( &KeyHandle,
  439. KEY_READ | KEY_WRITE,
  440. &Obja );
  441. if( !NT_SUCCESS(Status) ) {
  442. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InsertRegistrySzIntoMachineInfoBuffer: Exiting (1).\n")));
  443. return Status;
  444. }
  445. RtlInitUnicodeString( &UnicodeString, ValueName );
  446. KeyValueLength = 0;
  447. Status = ZwQueryValueKey( KeyHandle,
  448. &UnicodeString,
  449. KeyValuePartialInformation,
  450. (PVOID)NULL,
  451. 0,
  452. &KeyValueLength );
  453. if( KeyValueLength == 0 ) {
  454. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InsertRegistrySzIntoMachineInfoBuffer: Exiting (2).\n")));
  455. return Status;
  456. }
  457. KeyValueLength += 4;
  458. ValueBuffer = (PKEY_VALUE_PARTIAL_INFORMATION)ALLOCATE_POOL( KeyValueLength, GENERAL_POOL_TAG );
  459. if( ValueBuffer == NULL ) {
  460. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InsertRegistrySzIntoMachineInfoBuffer: Exiting (3).\n")));
  461. return Status;
  462. }
  463. Status = ZwQueryValueKey( KeyHandle,
  464. &UnicodeString,
  465. KeyValuePartialInformation,
  466. ValueBuffer,
  467. KeyValueLength,
  468. &KeyValueLength );
  469. if( !NT_SUCCESS(Status) ) {
  470. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InsertRegistrySzIntoMachineInfoBuffer: Exiting (4).\n")));
  471. FREE_POOL( &ValueBuffer );
  472. return Status;
  473. }
  474. AppendMessage( MachineInformationBuffer,
  475. MessageId,
  476. (PWSTR)ValueBuffer->Data );
  477. FREE_POOL( &ValueBuffer );
  478. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  479. KdPrint(("SAC InsertRegistrySzIntoMachineInfoBuffer: Exiting.\n")));
  480. return Status;
  481. }
  482. VOID
  483. InitializeMachineInformation(
  484. VOID
  485. )
  486. /*++
  487. Routine Description:
  488. This function initializes the global variable MachineInformationBuffer.
  489. We'll gather a whole bunch of information about the machine and fill
  490. in the buffer.
  491. Arguments:
  492. None.
  493. Return Value:
  494. None.
  495. --*/
  496. {
  497. #define MACHINEINFORMATIONBUFFER_SIZE (512 * sizeof(WCHAR))
  498. PWSTR COMPUTERNAME_KEY_NAME = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\ComputerName\\ComputerName";
  499. PWSTR COMPUTERNAME_VALUE_NAME = L"ComputerName";
  500. PWSTR PROCESSOR_ARCHITECTURE_KEY_NAME = L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Environment";
  501. PWSTR PROCESSOR_ARCHITECTURE_VALUE_NAME = L"PROCESSOR_ARCHITECTURE";
  502. PSTR XML_TAG = "MACHINEINFO";
  503. PSTR XML_HEADER0 = "\r\n<PROPERTY.ARRAY NAME=\"MACHINEINFO\" TYPE=\"string\">\r\n";
  504. PSTR XML_HEADER1 = "<VALUE.ARRAY>\r\n";
  505. PSTR XML_HEADER2 = "<VALUE>\"%ws\"</VALUE>\r\n";
  506. PSTR XML_FOOTER0 = "</VALUE.ARRAY>\r\n</PROPERTY.ARRAY>";
  507. NTSTATUS Status = STATUS_SUCCESS;
  508. SIZE_T i;
  509. RTL_OSVERSIONINFOEXW VersionInfo;
  510. PWSTR MyTemporaryBufferW = NULL;
  511. PHEADLESS_CMD_SET_BLUE_SCREEN_DATA BSBuffer;
  512. PUCHAR pch;
  513. ULONG len;
  514. GUID MyGUID;
  515. PCWSTR pwStr = NULL;
  516. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  517. KdPrint(("SAC Initialize Machine Information: Entering.\n")));
  518. if( MachineInformationBuffer != NULL ) {
  519. //
  520. // someone called us again!
  521. //
  522. IF_SAC_DEBUG( SAC_DEBUG_FUNC_TRACE_LOUD,
  523. KdPrint(("SAC Initialize Machine Information:: MachineInformationBuffer already initialzied.\n")));
  524. return;
  525. } else {
  526. MachineInformationBuffer = (PWCHAR)ALLOCATE_POOL( MACHINEINFORMATIONBUFFER_SIZE, GENERAL_POOL_TAG );
  527. if( MachineInformationBuffer == NULL ) {
  528. goto InitializeMachineInformation_Failure;
  529. }
  530. }
  531. RtlZeroMemory( MachineInformationBuffer, MACHINEINFORMATIONBUFFER_SIZE );
  532. //
  533. // We're real early in the boot process, so we're going to take for granted that the machine hasn't
  534. // bugchecked. This means that we can safely call some kernel functions to go figure out what
  535. // platform we're running on.
  536. //
  537. RtlZeroMemory( &VersionInfo, sizeof(VersionInfo));
  538. Status = RtlGetVersion( (POSVERSIONINFOW)&VersionInfo );
  539. if( !NT_SUCCESS(Status) ) {
  540. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeMachineInformation: Exiting (2).\n")));
  541. goto InitializeMachineInformation_Failure;
  542. }
  543. //
  544. // ========
  545. // Machine name.
  546. // ========
  547. //
  548. Status = InsertRegistrySzIntoMachineInfoBuffer( COMPUTERNAME_KEY_NAME,
  549. COMPUTERNAME_VALUE_NAME,
  550. SAC_MACHINEINFO_COMPUTERNAME );
  551. if( !NT_SUCCESS(Status) ) {
  552. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeMachineInformation: Exiting (20).\n")));
  553. goto InitializeMachineInformation_Failure;
  554. }
  555. //
  556. // ========
  557. // Machine GUID.
  558. // ========
  559. //
  560. // make sure.
  561. RtlZeroMemory( &MyGUID, sizeof(GUID) );
  562. i = sizeof(GUID);
  563. Status = HeadlessDispatch( HeadlessCmdQueryGUID,
  564. NULL,
  565. 0,
  566. &MyGUID,
  567. &i );
  568. if( !NT_SUCCESS(Status) ) {
  569. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeMachineInformation: Exiting (30).\n")));
  570. goto InitializeMachineInformation_Failure;
  571. }
  572. //
  573. // Allocate enough memory for the formatting message, plus the size of a
  574. // GUID-turned-text, which is 2x the number of bytes required to hold the binary,
  575. // plus 8 bytes of slop.
  576. //
  577. pwStr = GetMessage(SAC_MACHINEINFO_GUID);
  578. if( pwStr ) {
  579. MyTemporaryBufferW = (PWSTR)ALLOCATE_POOL( (sizeof(GUID)*2) + (wcslen(pwStr) + 8) * sizeof(WCHAR) , GENERAL_POOL_TAG );
  580. if( MyTemporaryBufferW == NULL ) {
  581. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeMachineInformation: Exiting (31).\n")));
  582. goto InitializeMachineInformation_Failure;
  583. }
  584. swprintf( MyTemporaryBufferW,
  585. GetMessage(SAC_MACHINEINFO_GUID),
  586. MyGUID.Data1,
  587. MyGUID.Data2,
  588. MyGUID.Data3,
  589. MyGUID.Data4[0],
  590. MyGUID.Data4[1],
  591. MyGUID.Data4[2],
  592. MyGUID.Data4[3],
  593. MyGUID.Data4[4],
  594. MyGUID.Data4[5],
  595. MyGUID.Data4[6],
  596. MyGUID.Data4[7] );
  597. wcscat( MachineInformationBuffer, MyTemporaryBufferW );
  598. FREE_POOL( &MyTemporaryBufferW );
  599. }
  600. //
  601. // ========
  602. // Processor Architecture.
  603. // ========
  604. //
  605. Status = InsertRegistrySzIntoMachineInfoBuffer( PROCESSOR_ARCHITECTURE_KEY_NAME,
  606. PROCESSOR_ARCHITECTURE_VALUE_NAME,
  607. SAC_MACHINEINFO_PROCESSOR_ARCHITECTURE );
  608. if( !NT_SUCCESS(Status) ) {
  609. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeMachineInformation: Exiting (40).\n")));
  610. goto InitializeMachineInformation_Failure;
  611. }
  612. //
  613. // ========
  614. // OS Name.
  615. // ========
  616. //
  617. //
  618. // Allocate enough memory for the formatting message, plus the size of 2 digits.
  619. // Currently, our versioning info is of the type "5.1", so we don't need much space
  620. // here, but let's be conservative and assume both major and minor version numbers
  621. // are 4 digits in size. That's 9 characters.
  622. //
  623. MyTemporaryBufferW = (PWSTR)ALLOCATE_POOL( (wcslen(GetMessage(SAC_MACHINEINFO_OS_VERSION)) + 9) * sizeof(WCHAR), GENERAL_POOL_TAG );
  624. if( MyTemporaryBufferW == NULL ) {
  625. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeMachineInformation: Exiting (50).\n")));
  626. goto InitializeMachineInformation_Failure;
  627. }
  628. swprintf( MyTemporaryBufferW,
  629. GetMessage(SAC_MACHINEINFO_OS_VERSION),
  630. VersionInfo.dwMajorVersion,
  631. VersionInfo.dwMinorVersion );
  632. wcscat( MachineInformationBuffer, MyTemporaryBufferW );
  633. FREE_POOL( &MyTemporaryBufferW );
  634. //
  635. // ========
  636. // Build Number.
  637. // ========
  638. //
  639. //
  640. // Allocate enough memory for the formatting message, plus the size of our build number.
  641. // Currently that's well below the 5-digit mark, but let's build some headroom here for
  642. // build numbers up to 99000 (5-digits).
  643. //
  644. MyTemporaryBufferW = (PWSTR)ALLOCATE_POOL( (wcslen(GetMessage(SAC_MACHINEINFO_OS_BUILD)) + 5) * sizeof(WCHAR), GENERAL_POOL_TAG );
  645. if( MyTemporaryBufferW == NULL ) {
  646. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeMachineInformation: Exiting (60).\n")));
  647. goto InitializeMachineInformation_Failure;
  648. }
  649. swprintf( MyTemporaryBufferW,
  650. GetMessage(SAC_MACHINEINFO_OS_BUILD),
  651. VersionInfo.dwBuildNumber );
  652. wcscat( MachineInformationBuffer, MyTemporaryBufferW );
  653. FREE_POOL( &MyTemporaryBufferW );
  654. //
  655. // ========
  656. // Product Type (and Suite).
  657. // ========
  658. //
  659. if( ExVerifySuite(DataCenter) ) {
  660. AppendMessage( MachineInformationBuffer,
  661. SAC_MACHINEINFO_OS_PRODUCTTYPE,
  662. (PWSTR)GetMessage(SAC_MACHINEINFO_DATACENTER) );
  663. } else if( ExVerifySuite(EmbeddedNT) ) {
  664. AppendMessage( MachineInformationBuffer,
  665. SAC_MACHINEINFO_OS_PRODUCTTYPE,
  666. (PWSTR)GetMessage(SAC_MACHINEINFO_EMBEDDED) );
  667. } else if( ExVerifySuite(Enterprise) ) {
  668. AppendMessage( MachineInformationBuffer,
  669. SAC_MACHINEINFO_OS_PRODUCTTYPE,
  670. (PWSTR)GetMessage(SAC_MACHINEINFO_ADVSERVER) );
  671. } else {
  672. //
  673. // We found no product suite that we recognized or cared about.
  674. // Assume we're running on a generic server.
  675. //
  676. AppendMessage( MachineInformationBuffer,
  677. SAC_MACHINEINFO_OS_PRODUCTTYPE,
  678. (PWSTR)GetMessage(SAC_MACHINEINFO_SERVER) );
  679. }
  680. //
  681. // ========
  682. // Service Pack Information.
  683. // ========
  684. //
  685. if( VersionInfo.wServicePackMajor != 0 ) {
  686. //
  687. // There's been a service pack applied. Better tell the user.
  688. //
  689. //
  690. // Allocate enough memory for the formatting message, plus the size of our servicepack number.
  691. // Currently that's well below the 5-digit mark, but let's build some headroom here for
  692. // service pack numbers up to 99000 (5-digits).
  693. //
  694. MyTemporaryBufferW = (PWSTR)ALLOCATE_POOL( (wcslen(GetMessage(SAC_MACHINEINFO_SERVICE_PACK)) + 5) * sizeof(WCHAR), GENERAL_POOL_TAG );
  695. if( MyTemporaryBufferW == NULL ) {
  696. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE, KdPrint(("SAC InitializeMachineInformation: Exiting (80).\n")));
  697. goto InitializeMachineInformation_Failure;
  698. }
  699. swprintf( MyTemporaryBufferW,
  700. GetMessage(SAC_MACHINEINFO_SERVICE_PACK),
  701. VersionInfo.wServicePackMajor,
  702. VersionInfo.wServicePackMinor );
  703. wcscat( MachineInformationBuffer, MyTemporaryBufferW );
  704. FREE_POOL( &MyTemporaryBufferW );
  705. } else {
  706. AppendMessage( MachineInformationBuffer, SAC_MACHINEINFO_NO_SERVICE_PACK, NULL );
  707. }
  708. //
  709. // ========
  710. // Insert it all into the BLUESCREEN data.
  711. // ========
  712. //
  713. //
  714. // How big is this going to be?
  715. //
  716. i = wcslen(MachineInformationBuffer);
  717. i += strlen(XML_TAG);
  718. i += strlen(XML_HEADER0);
  719. i += strlen(XML_HEADER1);
  720. i += strlen(XML_HEADER2);
  721. i += strlen(XML_FOOTER0);
  722. i += 8;
  723. BSBuffer = (PHEADLESS_CMD_SET_BLUE_SCREEN_DATA)ALLOCATE_POOL( i,
  724. GENERAL_POOL_TAG );
  725. if( BSBuffer == NULL ) {
  726. goto InitializeMachineInformation_Failure;
  727. }
  728. pch = &(BSBuffer->Data[0]);
  729. len = sprintf( (LPSTR)pch, XML_TAG );
  730. BSBuffer->ValueIndex = len+1;
  731. pch = pch+len+1;
  732. len = sprintf( (LPSTR)pch, "%s%s", XML_HEADER0, XML_HEADER1 );
  733. pch = pch + len;
  734. len = sprintf( (LPSTR)pch, XML_HEADER2, MachineInformationBuffer );
  735. strcat( (LPSTR)pch, XML_FOOTER0 );
  736. HeadlessDispatch( HeadlessCmdSetBlueScreenData,
  737. BSBuffer,
  738. wcslen(MachineInformationBuffer)+256,
  739. NULL,
  740. 0 );
  741. FREE_POOL( &BSBuffer );
  742. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  743. KdPrint(("SAC Initialize Machine Information: Exiting.\n")));
  744. return;
  745. InitializeMachineInformation_Failure:
  746. if( MachineInformationBuffer != NULL ) {
  747. FREE_POOL(&MachineInformationBuffer);
  748. MachineInformationBuffer = NULL;
  749. }
  750. IF_SAC_DEBUG(SAC_DEBUG_FUNC_TRACE,
  751. KdPrint(("SAC Initialize Machine Information: Exiting with error.\n")));
  752. return;
  753. }