2 * PROJECT: ReactOS Drivers
3 * LICENSE: BSD - See COPYING.ARM in the top level directory
4 * FILE: drivers/sac/driver/util.c
5 * PURPOSE: Driver for the Server Administration Console (SAC) for EMS
6 * PROGRAMMERS: ReactOS Portable Systems Group
9 /* INCLUDES *******************************************************************/
13 #include <ndk/rtlfuncs.h>
15 /* GLOBALS ********************************************************************/
17 PCHAR Utf8ConversionBuffer
;
18 ULONG Utf8ConversionBufferSize
= PAGE_SIZE
;
20 PSAC_MACHINE_INFO MachineInformation
;
22 PVOID RequestSacCmdEventObjectBody
;
23 PKEVENT RequestSacCmdEventWaitObjectBody
;
24 PVOID RequestSacCmdSuccessEventObjectBody
;
25 PKEVENT RequestSacCmdSuccessEventWaitObjectBody
;
26 PVOID RequestSacCmdFailureEventObjectBody
;
27 PKEVENT RequestSacCmdFailureEventWaitObjectBody
;
28 PFILE_OBJECT ServiceProcessFileObject
;
29 BOOLEAN HaveUserModeServiceCmdEventInfo
;
31 PSAC_MESSAGE_ENTRY GlobalMessageTable
;
32 ULONG GlobalMessageTableCount
;
34 LONG SerialPortConsumerIndex
, SerialPortProducerIndex
;
35 PCHAR SerialPortBuffer
;
37 /* FUNCTIONS ******************************************************************/
41 SacTranslateUtf8ToUnicode(IN CHAR Utf8Char
,
47 /* Find out how many valid characters we have in the buffer */
49 while (Utf8Buffer
[i
++] && (i
< 3));
51 /* If we have at least 3, shift everything by a byte */
54 /* The last input character goes at the end */
55 Utf8Buffer
[0] = Utf8Buffer
[1];
56 Utf8Buffer
[1] = Utf8Buffer
[2];
57 Utf8Buffer
[2] = Utf8Char
;
61 /* We don't have more than 3 characters, place the input at the index */
62 Utf8Buffer
[i
] = Utf8Char
;
65 /* Print to debugger */
66 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SacTranslateUtf8ToUnicode - About to decode the UTF8 buffer.\n");
67 SAC_DBG(SAC_DBG_ENTRY_EXIT
, " UTF8[0]: 0x%02lx UTF8[1]: 0x%02lx UTF8[2]: 0x%02lx\n",
72 /* Is this a simple ANSI character? */
73 if (!(Utf8Char
& 0x80))
75 /* Return it as Unicode, nothing left to do */
76 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SACDRV: SacTranslateUTf8ToUnicode - Case1\n");
77 *Utf8Value
= (WCHAR
)Utf8Char
;
78 Utf8Buffer
[0] = Utf8Buffer
[1];
79 Utf8Buffer
[1] = Utf8Buffer
[2];
80 Utf8Buffer
[2] = UNICODE_NULL
;
84 /* Anything else is not yet supported */
91 SacTranslateUnicodeToUtf8(IN PWCHAR SourceBuffer
,
92 IN ULONG SourceBufferLength
,
93 OUT PCHAR DestinationBuffer
,
94 IN ULONG DestinationBufferSize
,
96 OUT PULONG ProcessedCount
)
101 while ((*SourceBuffer
) &&
102 (*UTF8Count
< DestinationBufferSize
) &&
103 (*ProcessedCount
< SourceBufferLength
))
105 if (*SourceBuffer
& 0xFF80)
107 if (*SourceBuffer
& 0xF800)
109 if ((*UTF8Count
+ 3) >= DestinationBufferSize
) break;
110 DestinationBuffer
[*UTF8Count
] = ((*SourceBuffer
>> 12) & 0xF) | 0xE0;
112 DestinationBuffer
[*UTF8Count
] = ((*SourceBuffer
>> 6) & 0x3F) | 0x80;
116 if ((*UTF8Count
+ 2) >= DestinationBufferSize
) break;
117 DestinationBuffer
[*UTF8Count
] = ((*SourceBuffer
>> 6) & 31) | 0xC0;
120 DestinationBuffer
[*UTF8Count
] = (*SourceBuffer
& 0x3F) | 0x80;
124 DestinationBuffer
[*UTF8Count
] = (*SourceBuffer
& 0x7F);
132 ASSERT(*ProcessedCount
<= SourceBufferLength
);
133 ASSERT(*UTF8Count
<= DestinationBufferSize
);
139 GetMessage(IN ULONG MessageIndex
)
141 PSAC_MESSAGE_ENTRY MessageEntry
;
143 PWCHAR MessageData
= NULL
;
145 /* Loop all cached messages */
146 for (i
= 0; i
< GlobalMessageTableCount
; i
++)
148 /* Check if this one matches the index */
149 MessageEntry
= &GlobalMessageTable
[i
];
150 if (MessageEntry
->Index
== MessageIndex
)
152 /* It does, return the buffer */
153 MessageData
= MessageEntry
->Buffer
;
158 /* We should always find it */
159 if (!MessageData
) ASSERT(FALSE
);
165 UTF8EncodeAndSend(IN PWCHAR String
)
167 ULONG ProcessedCount
, Utf8Count
, i
;
168 NTSTATUS Status
= STATUS_SUCCESS
;
170 /* Call the translator routine */
171 if (SacTranslateUnicodeToUtf8(String
,
173 Utf8ConversionBuffer
,
174 Utf8ConversionBufferSize
,
178 /* Loop every character */
179 for (i
= 0; i
< Utf8Count
; i
++)
181 /* Send it to the terminal */
182 Status
= HeadlessDispatch(HeadlessCmdPutData
,
183 &Utf8ConversionBuffer
[i
],
184 sizeof(Utf8ConversionBuffer
[i
]),
187 if (!NT_SUCCESS(Status
)) break;
192 /* Conversion failed */
193 Status
= STATUS_UNSUCCESSFUL
;
202 SacFormatMessage(IN PWCHAR FormattedString
,
203 IN PWCHAR MessageString
,
204 IN ULONG MessageSize
)
206 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC SacFormatMessage: Entering.\n");
208 /* Check if any of the parameters are NULL or zero */
209 if (!(MessageString
) || !(FormattedString
) || !(MessageSize
))
211 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC SacFormatMessage: Exiting with invalid parameters.\n");
215 /* Keep going as long as there's still characters */
216 while ((MessageString
[0]) && (MessageSize
))
218 /* Is it a non-formatting character? */
219 if (MessageString
[0] != L
'%')
221 /* Just write it back into the buffer and keep going */
222 *FormattedString
++ = MessageString
[0];
227 /* Go over the format characters we recognize */
228 switch (MessageString
[1])
231 *FormattedString
= UNICODE_NULL
;
235 *FormattedString
++ = L
'%';
239 *FormattedString
++ = L
'\r';
240 *FormattedString
++ = L
'\n';
244 *FormattedString
++ = L
'\r';
248 *FormattedString
++ = L
' ';
252 *FormattedString
++ = L
'.';
256 *FormattedString
++ = L
'!';
260 /* Only move forward one character */
265 /* Move forward two characters */
269 /* Move to the next character*/
274 *FormattedString
= UNICODE_NULL
;
275 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC SacFormatMessage: Exiting.\n");
280 PreloadGlobalMessageTable(IN PVOID ImageBase
)
282 NTSTATUS Status
, Status2
;
283 ULONG MessageId
, TotalLength
, TextSize
, i
;
285 PMESSAGE_RESOURCE_ENTRY MessageEntry
;
287 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC PreloadGlobalMessageTable: Entering.\n");
289 /* Nothing to do if we already have a table */
290 Status
= STATUS_SUCCESS
;
291 if (GlobalMessageTable
) goto Exit
;
293 /* Loop through up to 200 messages */
295 for (MessageId
= 1; MessageId
!= SAC_MAX_MESSAGES
; MessageId
++)
297 /* Find this message ID in the string table*/
298 Status2
= RtlFindMessage(ImageBase
,
303 if (NT_SUCCESS(Status2
))
305 /* Make sure it's Unicode */
306 ASSERT(MessageEntry
->Flags
& MESSAGE_RESOURCE_UNICODE
);
308 /* Remove the space taken up by the OS header, and add our own */
309 TotalLength
+= MessageEntry
->Length
-
310 FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY
, Text
) +
311 sizeof(SAC_MESSAGE_ENTRY
);
313 /* One more in the table */
314 GlobalMessageTableCount
++;
318 /* We should've found at least one message... */
321 /* Bail out otherwise */
322 SAC_DBG(SAC_DBG_INIT
, "SAC PreloadGlobalMessageTable: No Messages.\n");
323 Status
= STATUS_INVALID_PARAMETER
;
327 /* Allocate space for the buffers and headers */
328 GlobalMessageTable
= SacAllocatePool(TotalLength
, GLOBAL_BLOCK_TAG
);
329 if (!GlobalMessageTable
)
331 /* Bail out if we couldn't allocate it */
332 Status
= STATUS_NO_MEMORY
;
336 /* All the buffers are going to be at the end of the table */
337 StringBuffer
= (PWCHAR
)(&GlobalMessageTable
[GlobalMessageTableCount
]);
339 /* Now loop over our entries again */
340 for (i
= 0, MessageId
= 1; MessageId
!= SAC_MAX_MESSAGES
; MessageId
++)
342 /* Make sure the message is still there...! */
343 Status2
= RtlFindMessage(ImageBase
,
348 if (NT_SUCCESS(Status2
))
350 /* Write the entry in the message table*/
351 GlobalMessageTable
[i
].Index
= MessageId
;
352 GlobalMessageTable
[i
].Buffer
= StringBuffer
;
354 /* The structure includes the size of the header, elide it */
355 TextSize
= MessageEntry
->Length
-
356 FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY
, Text
);
358 /* Format the message into the entry. It should be same or smaller */
359 SacFormatMessage(StringBuffer
, (PWCHAR
)MessageEntry
->Text
, TextSize
);
360 ASSERT((ULONG
)(wcslen(StringBuffer
)*sizeof(WCHAR
)) <= TextSize
);
362 /* Move to the next buffer space */
363 StringBuffer
+= (TextSize
/ sizeof(WCHAR
));
365 /* Move to the next entry, make sure the status is full success */
367 Status
= STATUS_SUCCESS
;
372 /* All done, return the status code */
373 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC TearDownGlobalMessageTable: Exiting with status 0x%0x\n", Status
);
379 TearDownGlobalMessageTable(VOID
)
381 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC TearDownGlobalMessageTable: Entering.\n");
383 /* Free the table if one existed */
384 if (GlobalMessageTable
) SacFreePool(GlobalMessageTable
);
386 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC TearDownGlobalMessageTable: Exiting\n");
387 return STATUS_SUCCESS
;
392 GetRegistryValueBuffer(IN PCWSTR KeyName
,
394 IN PKEY_VALUE_PARTIAL_INFORMATION
* Buffer
)
397 OBJECT_ATTRIBUTES ObjectAttributes
;
398 UNICODE_STRING DestinationString
;
400 SIZE_T ResultLength
= 0;
401 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC GetRegistryValueBuffer: Entering.\n");
402 CHECK_PARAMETER1(KeyName
);
403 CHECK_PARAMETER2(ValueName
);
405 /* Open the specified key */
406 RtlInitUnicodeString(&DestinationString
, KeyName
);
407 InitializeObjectAttributes(&ObjectAttributes
,
409 OBJ_CASE_INSENSITIVE
,
412 Status
= ZwOpenKey(&Handle
,
413 KEY_WRITE
| SYNCHRONIZE
| KEY_READ
,
415 if (!NT_SUCCESS(Status
))
417 /* Bail out on failure */
418 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC GetRegistryValueBuffer: failed ZwOpenKey: %X.\n", Status
);
422 /* Query the size of the key */
423 RtlInitUnicodeString(&DestinationString
, ValueName
);
424 Status
= ZwQueryValueKey(Handle
,
426 KeyValuePartialInformation
,
430 if (!ResultLength
) return Status
;
432 /* Allocate the buffer for the partial info structure and our integer data */
433 ResultLength
+= sizeof(ULONG
);
434 *Buffer
= SacAllocatePool(ResultLength
, GLOBAL_BLOCK_TAG
);
437 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC GetRegistryValueBuffer: failed allocation\n");
441 /* Now read the data */
442 Status
= ZwQueryValueKey(Handle
,
444 KeyValuePartialInformation
,
448 if (!NT_SUCCESS(Status
))
450 /* Free the buffer if we couldn't read the data */
451 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC GetRegistryValueBuffer: failed ZwQueryValueKey: %X.\n", Status
);
452 SacFreePool(*Buffer
);
455 /* Return the result */
456 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC SetRegistryValue: Exiting.\n");
462 SetRegistryValue(IN PCWSTR KeyName
,
469 OBJECT_ATTRIBUTES ObjectAttributes
;
470 UNICODE_STRING DestinationString
;
472 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC SetRegistryValue: Entering.\n");
473 CHECK_PARAMETER1(KeyName
);
474 CHECK_PARAMETER2(ValueName
);
475 CHECK_PARAMETER4(Data
);
477 /* Open the specified key */
478 RtlInitUnicodeString(&DestinationString
, KeyName
);
479 InitializeObjectAttributes(&ObjectAttributes
,
481 OBJ_CASE_INSENSITIVE
,
484 Status
= ZwOpenKey(&Handle
,
485 KEY_WRITE
| SYNCHRONIZE
| KEY_READ
,
487 if (!NT_SUCCESS(Status
))
489 /* Bail out on failure */
490 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC SetRegistryValue: failed ZwOpenKey: %X.\n", Status
);
494 /* Set the specified value */
495 RtlInitUnicodeString(&DestinationString
, ValueName
);
496 Status
= ZwSetValueKey(Handle
, &DestinationString
, 0, Type
, Data
, DataSize
);
497 if (!NT_SUCCESS(Status
))
499 /* Print error on failure */
500 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC SetRegistryValue: failed ZwSetValueKey: %X.\n", Status
);
503 /* Close the handle and exit */
505 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC SetRegistryValue: Exiting.\n");
511 CopyRegistryValueData(IN PVOID
* Buffer
,
512 IN PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
)
514 NTSTATUS Status
= STATUS_SUCCESS
;
515 CHECK_PARAMETER1(Buffer
);
516 CHECK_PARAMETER2(PartialInfo
);
518 /* Allocate space for registry data */
519 *Buffer
= SacAllocatePool(PartialInfo
->DataLength
, GLOBAL_BLOCK_TAG
);
522 /* Copy the data into the buffer */
523 RtlCopyMemory(*Buffer
, PartialInfo
->Data
, PartialInfo
->DataLength
);
527 /* Set the correct error code */
528 SAC_DBG(SAC_DBG_UTIL
, "SAC CopyRegistryValueBuffer: Failed ALLOCATE.\n");
529 Status
= STATUS_NO_MEMORY
;
532 /* Return the result */
538 TranslateMachineInformationXML(IN PWCHAR
*Buffer
,
544 CHECK_PARAMETER1(Buffer
);
546 /* Start by believing the world is beautiful */
547 Status
= STATUS_SUCCESS
;
549 /* First, the header */
550 Size
= wcslen(L
"<machine-info>\r\n");
552 /* Do we have a machine name? */
553 if (MachineInformation
->MachineName
)
555 /* Go and add it in */
556 Size
+= wcslen(MachineInformation
->MachineName
);
557 Size
+= wcslen(L
"<name>%s</name>\r\n");
560 /* Do we have a GUID? */
561 if (MachineInformation
->MachineGuid
)
563 /* Go and add it in */
564 Size
+= wcslen(MachineInformation
->MachineGuid
);
565 Size
+= wcslen(L
"<guid>%s</guid>\r\n");
568 /* Do we know the processor? */
569 if (MachineInformation
->ProcessorArchitecture
)
571 /* Go and add it in */
572 Size
+= wcslen(MachineInformation
->ProcessorArchitecture
);
573 Size
+= wcslen(L
"<processor-architecture>%s</processor-architecture>\r\n");
576 /* Do we have the version? */
577 if (MachineInformation
->MajorVersion
)
579 /* Go and add it in */
580 Size
+= wcslen(MachineInformation
->MajorVersion
);
581 Size
+= wcslen(L
"<os-version>%s</os-version>\r\n");
584 /* Do we have the build? */
585 if (MachineInformation
->BuildNumber
)
587 /* Go and add it in */
588 Size
+= wcslen(MachineInformation
->BuildNumber
);
589 Size
+= wcslen(L
"<os-build-number>%s</os-build-number>\r\n");
592 /* Do we have the product type? */
593 if (MachineInformation
->ProductType
)
595 /* Go and add it in */
596 Size
+= wcslen(MachineInformation
->ProductType
);
597 Size
+= wcslen(L
"<os-product>%s</os-product>\r\n");
600 /* Do we have a service pack? */
601 if (MachineInformation
->ServicePack
)
603 /* Go and add it in */
604 Size
+= wcslen(MachineInformation
->ServicePack
);
605 Size
+= wcslen(L
"<os-service-pack>%s</os-service-pack>\r\n");
608 /* Anything else we need to know? Add it in too */
609 if (ExtraData
) Size
+= wcslen(ExtraData
);
611 /* Finally, add the footer */
612 Size
+= wcslen(L
"</machine-info>\r\n");
614 /* Convert to bytes and add a NULL */
615 Size
+= sizeof(ANSI_NULL
);
616 Size
*= sizeof(WCHAR
);
618 /* Allocate space for the buffer */
619 p
= SacAllocatePool(Size
, GLOBAL_BLOCK_TAG
);
621 if (!p
) return STATUS_NO_MEMORY
;
623 wcscpy(p
, L
"<machine-info>\r\n");
624 p
+= wcslen(L
"<machine-info>\r\n");
626 if (MachineInformation
->MachineName
)
629 L
"<name>%s</name>\r\n",
630 MachineInformation
->MachineName
);
633 if (MachineInformation
->MachineGuid
)
636 L
"<guid>%s</guid>\r\n",
637 MachineInformation
->MachineGuid
);
640 if (MachineInformation
->ProcessorArchitecture
)
643 L
"<processor-architecture>%s</processor-architecture>\r\n",
644 MachineInformation
->ProcessorArchitecture
);
647 if (MachineInformation
->MajorVersion
)
650 L
"<os-version>%s</os-version>\r\n",
651 MachineInformation
->MajorVersion
);
654 if (MachineInformation
->BuildNumber
)
657 L
"<os-build-number>%s</os-build-number>\r\n",
658 MachineInformation
->BuildNumber
);
661 if (MachineInformation
->ProductType
)
664 L
"<os-product>%s</os-product>\r\n",
665 MachineInformation
->ProductType
);
668 if (MachineInformation
->ServicePack
)
671 L
"<os-service-pack>%s</os-service-pack>\r\n",
672 MachineInformation
->ServicePack
);
677 wcscpy(p
, ExtraData
);
678 p
+= wcslen(ExtraData
);
681 wcscpy(p
, L
"</machine-info>\r\n");
682 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "MachineInformation: %S\n", *Buffer
);
683 ASSERT((((ULONG
)wcslen(*Buffer
) + 1) * sizeof(WCHAR
)) <= Size
);
689 InitializeMachineInformation(VOID
)
692 PWCHAR GuidString
, MajorVersion
, ServicePack
, BuildNumber
, MessageBuffer
;
694 ULONG SuiteTypeMessage
;
695 BOOLEAN SetupInProgress
= FALSE
;
697 ULONG RealSize
, Size
, OutputSize
;
698 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo
;
699 RTL_OSVERSIONINFOEXW VersionInformation
;
700 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC Initialize Machine Information : Entering.\n");
702 /* Don't do anything if we already queried this */
703 if (MachineInformation
)
705 SAC_DBG(SAC_DBG_MACHINE
, "SAC Initialize Machine Information:: MachineInformationBuffer already initialized.\n");
709 /* Allocate the machine information */
710 MachineInformation
= SacAllocatePool(sizeof(*MachineInformation
),
712 if (!MachineInformation
)
717 /* Zero it out for now */
718 RtlZeroMemory(MachineInformation
, sizeof(*MachineInformation
));
720 /* Query OS version */
721 RtlZeroMemory(&VersionInformation
, sizeof(VersionInformation
));
722 VersionInformation
.dwOSVersionInfoSize
= sizeof(VersionInformation
);
723 Status
= RtlGetVersion((PRTL_OSVERSIONINFOW
)&VersionInformation
);
724 if (!NT_SUCCESS(Status
))
726 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC InitializeMachineInformation: Exiting (2).\n");
730 /* Check if setup is in progress */
731 Status
= GetRegistryValueBuffer(L
"\\Registry\\Machine\\System\\Setup",
732 L
"SystemSetupInProgress",
734 if (NT_SUCCESS(Status
))
736 /* The key is there, is the value set? */
737 if (*(PULONG
)PartialInfo
->Data
) SetupInProgress
= TRUE
;
738 SacFreePool(PartialInfo
);
741 /* Yes, so we'll use a special hostname to identify this */
742 MessageBuffer
= GetMessage(SAC_UNINITIALIZED_MSG
);
743 Size
= wcslen(MessageBuffer
);
745 RealSize
= Size
* sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
747 /* Make room for it and copy it in there */
748 MachineInformation
->MachineName
= SacAllocatePool(RealSize
,
750 if (MachineInformation
->MachineName
)
752 wcscpy(MachineInformation
->MachineName
, MessageBuffer
);
757 /* If we are not in setup mode, or if we failed to check... */
758 if (!SetupInProgress
)
760 /* Query the computer name */
761 Status
= GetRegistryValueBuffer(L
"\\Registry\\Machine\\System\\"
762 L
"CurrentControlSet\\Control\\"
763 L
"ComputerName\\ComputerName",
766 if (!NT_SUCCESS(Status
))
768 /* It's not critical, but we won't have it */
769 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC InitializeMachineInformation: Failed to get machine name.\n");
773 /* We have the name, copy it from the registry */
774 Status
= CopyRegistryValueData((PVOID
*)&MachineInformation
->
777 SacFreePool(PartialInfo
);
778 if (!NT_SUCCESS(Status
))
780 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC InitializeMachineInformation: Exiting (20).\n");
786 /* Next step, try to get the machine GUID */
787 RtlZeroMemory(&SystemGuid
, sizeof(SystemGuid
));
788 OutputSize
= sizeof(SystemGuid
);
789 Status
= HeadlessDispatch(HeadlessCmdQueryGUID
,
794 if (!NT_SUCCESS(Status
))
796 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC InitializeMachineInformation: Failed to get Machine GUID.\n");
800 /* We have it -- make room for it */
801 GuidString
= SacAllocatePool(0x50, GLOBAL_BLOCK_TAG
);
804 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC InitializeMachineInformation: Exiting (31).\n");
808 /* Build the string with the GUID in it, and save the ppointer to it */
810 L
"%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
821 SystemGuid
.Data4
[7]);
822 MachineInformation
->MachineGuid
= GuidString
;
825 /* Next, query the processor architecture */
826 Status
= GetRegistryValueBuffer(L
"\\Registry\\Machine\\System\\"
827 L
"CurrentControlSet\\Control\\"
828 L
"Session Manager\\Environment",
829 L
"PROCESSOR_ARCHITECTURE",
831 if (!NT_SUCCESS(Status
))
833 /* It's not critical, but we won't have it */
834 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC InitializeMachineInformation: Exiting (30).\n");
838 /* We have it! Copy the value from the registry */
839 Status
= CopyRegistryValueData((PVOID
*)&MachineInformation
->
840 ProcessorArchitecture
,
842 SacFreePool(PartialInfo
);
843 if (!NT_SUCCESS(Status
))
845 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC InitializeMachineInformation: Exiting (30).\n");
850 /* Now allocate a buffer for the OS version number */
851 MajorVersion
= SacAllocatePool(0x18, GLOBAL_BLOCK_TAG
);
854 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC InitializeMachineInformation: Exiting (50).\n");
858 /* Build the buffer and set a pointer to it */
859 swprintf(MajorVersion
,
861 VersionInformation
.dwMajorVersion
,
862 VersionInformation
.dwMinorVersion
);
863 MachineInformation
->MajorVersion
= MajorVersion
;
865 /* Now allocate a buffer for the OS build number */
866 BuildNumber
= SacAllocatePool(0xC, GLOBAL_BLOCK_TAG
);
869 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC InitializeMachineInformation: Exiting (60).\n");
873 /* Build the buffer and set a pointer to it */
874 swprintf(BuildNumber
, L
"%d", VersionInformation
.dwBuildNumber
);
875 MachineInformation
->BuildNumber
= BuildNumber
;
877 /* Now check what kind of SKU this is */
878 if (ExVerifySuite(DataCenter
))
880 SuiteTypeMessage
= SAC_DATACENTER_SUITE_MSG
;
882 else if (ExVerifySuite(EmbeddedNT
))
884 SuiteTypeMessage
= SAC_EMBEDDED_SUITE_MSG
;
886 else if (ExVerifySuite(Enterprise
))
888 SuiteTypeMessage
= SAC_ENTERPRISE_SUITE_MSG
;
892 /* Unknown or perhaps a client SKU */
893 SuiteTypeMessage
= SAC_NO_SUITE_MSG
;
896 /* Get the string that corresponds to the SKU type */
897 MessageBuffer
= GetMessage(SuiteTypeMessage
);
900 /* We won't have it, but this isn't critical */
901 SAC_DBG(SAC_DBG_INIT
, "SAC InitializeMachineInformation: Failed to get product type.\n");
905 /* Calculate the size we need to hold the string */
906 Size
= wcslen(MessageBuffer
);
908 RealSize
= Size
* sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
910 /* Allocate a buffer for it */
911 ProductType
= SacAllocatePool(RealSize
, GLOBAL_BLOCK_TAG
);
914 SAC_DBG(SAC_DBG_INIT
, "SAC InitializeMachineInformation: Failed product type memory allocation.\n");
918 /* Copy the string and set the pointer */
919 RtlCopyMemory(ProductType
, MessageBuffer
, RealSize
);
920 MachineInformation
->ProductType
= ProductType
;
923 /* Check if this is a SP version or RTM version */
924 if (VersionInformation
.wServicePackMajor
)
926 /* This is a service pack, allocate a buffer for the version */
927 ServicePack
= SacAllocatePool(0x18, GLOBAL_BLOCK_TAG
);
930 /* Build the buffer and set a pointer to it */
931 swprintf(ServicePack
,
933 VersionInformation
.wServicePackMajor
,
934 VersionInformation
.wServicePackMinor
);
935 MachineInformation
->ServicePack
= ServicePack
;
937 /* We've collected all the machine info and are done! */
941 /* This is the failure path */
942 SAC_DBG(SAC_DBG_INIT
, "SAC InitializeMachineInformation: Failed service pack memory allocation.\n");
946 /* Get a generic string that indicates there's no service pack */
947 MessageBuffer
= GetMessage(SAC_NO_DATA_MSG
);
948 Size
= wcslen(MessageBuffer
);
950 RealSize
= Size
* sizeof(WCHAR
) + sizeof(UNICODE_NULL
);
952 /* Allocate memory for the "no service pack" string */
953 ServicePack
= SacAllocatePool(RealSize
, GLOBAL_BLOCK_TAG
);
956 /* Copy the buffer and set a pointer to it */
957 RtlCopyMemory(ServicePack
, MessageBuffer
, RealSize
);
958 MachineInformation
->ServicePack
= ServicePack
;
960 /* We've collected all the machine info and are done! */
964 SAC_DBG(SAC_DBG_INIT
, "SAC InitializeMachineInformation: Failed service pack memory allocation.\n");
968 /* In the failure path, always cleanup the machine information buffer */
969 if (MachineInformation
)
971 SacFreePool(MachineInformation
);
973 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC Initialize Machine Information : Exiting with error.\n");
978 GetCommandConsoleLaunchingPermission(OUT PBOOLEAN Permission
)
981 PKEY_VALUE_PARTIAL_INFORMATION Dummy
;
983 /* Assume success and read the key */
985 Status
= GetRegistryValueBuffer(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacdrv",
986 L
"DisableCmdSessions",
988 if (Status
== STATUS_OBJECT_NAME_NOT_FOUND
)
990 /* The default is success */
991 Status
= STATUS_SUCCESS
;
995 /* Only if the key is present and set, do we disable permission */
996 if (NT_SUCCESS(Status
)) *Permission
= FALSE
;
1005 ImposeSacCmdServiceStartTypePolicy(VOID
)
1008 PKEY_VALUE_PARTIAL_INFORMATION Buffer
= NULL
;
1011 /* Read the service start type*/
1012 Status
= GetRegistryValueBuffer(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacsvr",
1015 if (!NT_SUCCESS(Status
)) return Status
;
1017 /* If there's no start type, fail, as this is unusual */
1018 if (!Buffer
) return STATUS_UNSUCCESSFUL
;
1020 /* Read the value */
1021 Status
= CopyRegistryValueData((PVOID
*)&Data
, Buffer
);
1022 SacFreePool(Buffer
);
1023 if (!NT_SUCCESS(Status
)) return Status
;
1025 /* Check what the current start type is */
1028 /* It's boot, system, or disabled */
1032 /* Leave it as is */
1037 /* It's set to automatic, set it to system instead */
1039 Status
= SetRegistryValue(L
"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacsvr",
1044 if (!NT_SUCCESS(Status
))
1046 SAC_DBG(SAC_DBG_INIT
, "SAC ImposeSacCmdServiceStartTypePolicy: Failed SetRegistryValue: %X\n", Status
);
1059 InitializeCmdEventInfo(VOID
)
1061 /* Check if we were already initialized */
1062 if (HaveUserModeServiceCmdEventInfo
)
1064 /* Full state expected */
1065 ASSERT(RequestSacCmdEventObjectBody
);
1066 ASSERT(RequestSacCmdSuccessEventObjectBody
);
1067 ASSERT(RequestSacCmdFailureEventObjectBody
);
1069 /* Dereference each wait object in turn */
1070 if (RequestSacCmdEventObjectBody
)
1072 ObDereferenceObject(RequestSacCmdEventObjectBody
);
1075 if (RequestSacCmdSuccessEventObjectBody
)
1077 ObDereferenceObject(RequestSacCmdSuccessEventObjectBody
);
1080 if (RequestSacCmdFailureEventObjectBody
)
1082 ObDereferenceObject(RequestSacCmdFailureEventObjectBody
);
1086 /* Claer everything */
1087 RequestSacCmdEventObjectBody
= NULL
;
1088 RequestSacCmdEventWaitObjectBody
= NULL
;
1089 RequestSacCmdSuccessEventObjectBody
= NULL
;
1090 RequestSacCmdSuccessEventWaitObjectBody
= NULL
;
1091 RequestSacCmdFailureEventObjectBody
= NULL
;
1092 RequestSacCmdFailureEventWaitObjectBody
= NULL
;
1093 ServiceProcessFileObject
= NULL
;
1096 HaveUserModeServiceCmdEventInfo
= FALSE
;
1101 RegisterBlueScreenMachineInformation(VOID
)
1104 PHEADLESS_CMD_SET_BLUE_SCREEN_DATA BsBuffer
;
1105 ULONG Length
, HeaderLength
, TotalLength
;
1109 /* Create the XML buffer and make sure it's OK */
1110 Status
= TranslateMachineInformationXML(&XmlBuffer
, NULL
);
1111 CHECK_PARAMETER_WITH_STATUS(NT_SUCCESS(Status
), Status
);
1112 CHECK_PARAMETER_WITH_STATUS(XmlBuffer
, STATUS_UNSUCCESSFUL
);
1114 /* Compute the sizes and allocate a buffer for it */
1115 Length
= wcslen(XmlBuffer
);
1116 HeaderLength
= strlen("MACHINEINFO");
1117 TotalLength
= HeaderLength
+
1120 2 * sizeof(ANSI_NULL
);
1121 BsBuffer
= SacAllocatePool(TotalLength
, GLOBAL_BLOCK_TAG
);
1122 CHECK_PARAMETER_WITH_STATUS(BsBuffer
, STATUS_NO_MEMORY
);
1124 /* Copy the XML property name */
1125 strcpy((PCHAR
)BsBuffer
->Data
, "MACHINEINFO");
1126 BsBuffer
->ValueIndex
= HeaderLength
+ sizeof(ANSI_NULL
);
1128 /* Copy the data and NULL-terminate it */
1129 for (i
= 0; i
< Length
; i
++)
1131 BsBuffer
->Data
[BsBuffer
->ValueIndex
+ i
] = XmlBuffer
[i
];
1133 BsBuffer
->Data
[BsBuffer
->ValueIndex
+ i
] = ANSI_NULL
;
1135 /* Let the OS save the buffer for later */
1136 Status
= HeadlessDispatch(HeadlessCmdSetBlueScreenData
,
1142 /* Failure or not, we don't need this anymore */
1143 SacFreePool(BsBuffer
);
1144 SacFreePool(XmlBuffer
);
1146 /* Return the result */
1147 SAC_DBG(SAC_DBG_ENTRY_EXIT
, "SAC Initialize Machine Information: Exiting.\n");
1153 FreeMachineInformation(VOID
)
1155 ASSERT(MachineInformation
);
1157 /* Free every cached string of machine information */
1158 if (MachineInformation
->MachineName
) SacFreePool(MachineInformation
);
1159 if (MachineInformation
->MachineGuid
) SacFreePool(MachineInformation
->MachineGuid
);
1160 if (MachineInformation
->ProcessorArchitecture
) SacFreePool(MachineInformation
->ProcessorArchitecture
);
1161 if (MachineInformation
->MajorVersion
) SacFreePool(MachineInformation
->MajorVersion
);
1162 if (MachineInformation
->BuildNumber
) SacFreePool(MachineInformation
->BuildNumber
);
1163 if (MachineInformation
->ProductType
) SacFreePool(MachineInformation
->ProductType
);
1164 if (MachineInformation
->ServicePack
) SacFreePool(MachineInformation
->ServicePack
);
1169 VerifyEventWaitable(IN HANDLE Handle
,
1170 OUT PVOID
*WaitObject
,
1171 OUT PVOID
*ActualWaitObject
)
1175 POBJECT_TYPE ObjectType
;
1177 /* Reference the object */
1178 Status
= ObReferenceObjectByHandle(Handle
,
1184 *WaitObject
= Object
;
1185 if (!NT_SUCCESS(Status
))
1187 SAC_DBG(SAC_DBG_INIT
, "SAC VerifyEventWaitable: Unable to reference event object (%lx)\n", Status
);
1191 /* Check if the object itself is NOT being used */
1192 ObjectType
= OBJECT_TO_OBJECT_HEADER(Object
)->Type
;
1193 if (ObjectType
->TypeInfo
.UseDefaultObject
== FALSE
)
1195 /* Get the actual object that's being used for the wait */
1196 *ActualWaitObject
= (PVOID
)((ULONG_PTR
)Object
+
1197 (ULONG_PTR
)ObjectType
->DefaultObject
);
1201 /* Drop the reference we took */
1202 SAC_DBG(SAC_DBG_INIT
, "SAC VerifyEventWaitable: event object not waitable!\n");
1203 ObDereferenceObject(*WaitObject
);
1209 SerialBufferGetChar(OUT PCHAR Char
)
1211 /* Check if nothing's been produced yet */
1212 if (SerialPortConsumerIndex
== SerialPortProducerIndex
)
1214 return STATUS_NO_DATA_DETECTED
;
1217 /* Consume the produced character and clear it*/
1218 *Char
= SerialPortBuffer
[SerialPortConsumerIndex
];
1219 SerialPortBuffer
[SerialPortConsumerIndex
] = ANSI_NULL
;
1221 /* Advance the index and return success */
1222 _InterlockedExchange(&SerialPortConsumerIndex
,
1223 (SerialPortConsumerIndex
+ 1) &
1224 (SAC_SERIAL_PORT_BUFFER_SIZE
- 1));
1225 return STATUS_SUCCESS
;
1230 GetMessageLineCount(IN ULONG MessageIndex
)
1232 ULONG LineCount
= 0;
1235 /* Get the message buffer */
1236 Buffer
= GetMessage(MessageIndex
);
1239 /* Scan it looking for new lines, and increment the count each time */
1240 while (*Buffer
) if (*Buffer
++ == L
'\n') ++LineCount
;
1243 /* Return the line count */
1248 ConvertAnsiToUnicode(
1254 return STATUS_NOT_IMPLEMENTED
;
1258 IsCmdEventRegistrationProcess(
1259 IN PFILE_OBJECT FileObject
1266 InvokeUserModeService(
1270 return STATUS_NOT_IMPLEMENTED
;
1274 TranslateMachineInformationText(
1277 return STATUS_NOT_IMPLEMENTED
;
1281 CopyAndInsertStringAtInterval(
1282 IN PWCHAR SourceStr
,
1284 IN PWCHAR InsertStr
,
1288 return STATUS_NOT_IMPLEMENTED
;
1292 RegisterSacCmdEvent(
1294 IN PKEVENT SetupCmdEvent
[]
1297 return STATUS_NOT_IMPLEMENTED
;
1301 UnregisterSacCmdEvent(
1302 IN PFILE_OBJECT FileObject
1305 return STATUS_NOT_IMPLEMENTED
;