Reactos
1/*
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
7 */
8
9/* INCLUDES *******************************************************************/
10
11#include "sacdrv.h"
12
13#include <ndk/rtlfuncs.h>
14
15/* GLOBALS ********************************************************************/
16
17PCHAR Utf8ConversionBuffer;
18ULONG Utf8ConversionBufferSize = PAGE_SIZE;
19
20PSAC_MACHINE_INFO MachineInformation;
21
22PVOID RequestSacCmdEventObjectBody;
23PKEVENT RequestSacCmdEventWaitObjectBody;
24PVOID RequestSacCmdSuccessEventObjectBody;
25PKEVENT RequestSacCmdSuccessEventWaitObjectBody;
26PVOID RequestSacCmdFailureEventObjectBody;
27PKEVENT RequestSacCmdFailureEventWaitObjectBody;
28PFILE_OBJECT ServiceProcessFileObject;
29BOOLEAN HaveUserModeServiceCmdEventInfo;
30
31PSAC_MESSAGE_ENTRY GlobalMessageTable;
32ULONG GlobalMessageTableCount;
33
34LONG SerialPortConsumerIndex, SerialPortProducerIndex;
35PCHAR SerialPortBuffer;
36
37/* FUNCTIONS ******************************************************************/
38
39BOOLEAN
40NTAPI
41SacTranslateUtf8ToUnicode(IN CHAR Utf8Char,
42 IN PCHAR Utf8Buffer,
43 OUT PWCHAR Utf8Value)
44{
45 ULONG i;
46
47 /* Find out how many valid characters we have in the buffer */
48 i = 0;
49 while (Utf8Buffer[i++] && (i < 3));
50
51 /* If we have at least 3, shift everything by a byte */
52 if (i >= 3)
53 {
54 /* The last input character goes at the end */
55 Utf8Buffer[0] = Utf8Buffer[1];
56 Utf8Buffer[1] = Utf8Buffer[2];
57 Utf8Buffer[2] = Utf8Char;
58 }
59 else
60 {
61 /* We don't have more than 3 characters, place the input at the index */
62 Utf8Buffer[i] = Utf8Char;
63 }
64
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",
68 Utf8Buffer[0],
69 Utf8Buffer[1],
70 Utf8Buffer[2]);
71
72 /* Is this a simple ANSI character? */
73 if (!(Utf8Char & 0x80))
74 {
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;
81 return TRUE;
82 }
83
84 /* Anything else is not yet supported */
85 ASSERT(FALSE);
86 return FALSE;
87}
88
89BOOLEAN
90NTAPI
91SacTranslateUnicodeToUtf8(IN PWCHAR SourceBuffer,
92 IN ULONG SourceBufferLength,
93 OUT PCHAR DestinationBuffer,
94 IN ULONG DestinationBufferSize,
95 OUT PULONG UTF8Count,
96 OUT PULONG ProcessedCount)
97{
98 *UTF8Count = 0;
99 *ProcessedCount = 0;
100
101 while ((*SourceBuffer) &&
102 (*UTF8Count < DestinationBufferSize) &&
103 (*ProcessedCount < SourceBufferLength))
104 {
105 if (*SourceBuffer & 0xFF80)
106 {
107 if (*SourceBuffer & 0xF800)
108 {
109 if ((*UTF8Count + 3) >= DestinationBufferSize) break;
110 DestinationBuffer[*UTF8Count] = ((*SourceBuffer >> 12) & 0xF) | 0xE0;
111 ++*UTF8Count;
112 DestinationBuffer[*UTF8Count] = ((*SourceBuffer >> 6) & 0x3F) | 0x80;
113 }
114 else
115 {
116 if ((*UTF8Count + 2) >= DestinationBufferSize) break;
117 DestinationBuffer[*UTF8Count] = ((*SourceBuffer >> 6) & 31) | 0xC0;
118 }
119 ++*UTF8Count;
120 DestinationBuffer[*UTF8Count] = (*SourceBuffer & 0x3F) | 0x80;
121 }
122 else
123 {
124 DestinationBuffer[*UTF8Count] = (*SourceBuffer & 0x7F);
125 }
126
127 ++*UTF8Count;
128 ++*ProcessedCount;
129 ++SourceBuffer;
130 }
131
132 ASSERT(*ProcessedCount <= SourceBufferLength);
133 ASSERT(*UTF8Count <= DestinationBufferSize);
134 return TRUE;
135}
136
137PWCHAR
138NTAPI
139GetMessage(IN ULONG MessageIndex)
140{
141 PSAC_MESSAGE_ENTRY MessageEntry;
142 ULONG i;
143 PWCHAR MessageData = NULL;
144
145 /* Loop all cached messages */
146 for (i = 0; i < GlobalMessageTableCount; i++)
147 {
148 /* Check if this one matches the index */
149 MessageEntry = &GlobalMessageTable[i];
150 if (MessageEntry->Index == MessageIndex)
151 {
152 /* It does, return the buffer */
153 MessageData = MessageEntry->Buffer;
154 break;
155 }
156 }
157
158 /* We should always find it */
159 if (!MessageData) ASSERT(FALSE);
160 return MessageData;
161}
162
163NTSTATUS
164NTAPI
165UTF8EncodeAndSend(IN PWCHAR String)
166{
167 ULONG ProcessedCount, Utf8Count, i;
168 NTSTATUS Status = STATUS_SUCCESS;
169
170 /* Call the translator routine */
171 if (SacTranslateUnicodeToUtf8(String,
172 wcslen(String),
173 Utf8ConversionBuffer,
174 Utf8ConversionBufferSize,
175 &Utf8Count,
176 &ProcessedCount))
177 {
178 /* Loop every character */
179 for (i = 0; i < Utf8Count; i++)
180 {
181 /* Send it to the terminal */
182 Status = HeadlessDispatch(HeadlessCmdPutData,
183 &Utf8ConversionBuffer[i],
184 sizeof(Utf8ConversionBuffer[i]),
185 NULL,
186 NULL);
187 if (!NT_SUCCESS(Status)) break;
188 }
189 }
190 else
191 {
192 /* Conversion failed */
193 Status = STATUS_UNSUCCESSFUL;
194 }
195
196 /* All done */
197 return Status;
198}
199
200VOID
201NTAPI
202SacFormatMessage(IN PWCHAR FormattedString,
203 IN PWCHAR MessageString,
204 IN ULONG MessageSize)
205{
206 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SacFormatMessage: Entering.\n");
207
208 /* Check if any of the parameters are NULL or zero */
209 if (!(MessageString) || !(FormattedString) || !(MessageSize))
210 {
211 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SacFormatMessage: Exiting with invalid parameters.\n");
212 return;
213 }
214
215 /* Keep going as long as there's still characters */
216 while ((MessageString[0]) && (MessageSize))
217 {
218 /* Is it a non-formatting character? */
219 if (MessageString[0] != L'%')
220 {
221 /* Just write it back into the buffer and keep going */
222 *FormattedString++ = MessageString[0];
223 MessageString++;
224 }
225 else
226 {
227 /* Go over the format characters we recognize */
228 switch (MessageString[1])
229 {
230 case L'0':
231 *FormattedString = UNICODE_NULL;
232 return;
233
234 case L'%':
235 *FormattedString++ = L'%';
236 break;
237
238 case L'\\':
239 *FormattedString++ = L'\r';
240 *FormattedString++ = L'\n';
241 break;
242
243 case L'r':
244 *FormattedString++ = L'\r';
245 break;
246
247 case L'b':
248 *FormattedString++ = L' ';
249 break;
250
251 case L'.':
252 *FormattedString++ = L'.';
253 break;
254
255 case L'!':
256 *FormattedString++ = L'!';
257 break;
258
259 default:
260 /* Only move forward one character */
261 MessageString--;
262 break;
263 }
264
265 /* Move forward two characters */
266 MessageString += 2;
267 }
268
269 /* Move to the next character*/
270 MessageSize--;
271 }
272
273 /* All done */
274 *FormattedString = UNICODE_NULL;
275 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SacFormatMessage: Exiting.\n");
276}
277
278NTSTATUS
279NTAPI
280PreloadGlobalMessageTable(IN PVOID ImageBase)
281{
282 NTSTATUS Status, Status2;
283 ULONG MessageId, TotalLength, TextSize, i;
284 PWCHAR StringBuffer;
285 PMESSAGE_RESOURCE_ENTRY MessageEntry;
286 PAGED_CODE();
287 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC PreloadGlobalMessageTable: Entering.\n");
288
289 /* Nothing to do if we already have a table */
290 Status = STATUS_SUCCESS;
291 if (GlobalMessageTable) goto Exit;
292
293 /* Loop through up to 200 messages */
294 TotalLength = 0;
295 for (MessageId = 1; MessageId != SAC_MAX_MESSAGES; MessageId++)
296 {
297 /* Find this message in the message table */
298 Status2 = RtlFindMessage(ImageBase,
299 RT_MESSAGETABLE,
300 MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
301 MessageId,
302 &MessageEntry);
303 if (NT_SUCCESS(Status2))
304 {
305 /* Make sure it's Unicode */
306 ASSERT(MessageEntry->Flags & MESSAGE_RESOURCE_UNICODE);
307
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);
312
313 /* One more in the table */
314 GlobalMessageTableCount++;
315 }
316 }
317
318 /* We should've found at least one message... */
319 if (!TotalLength)
320 {
321 /* Bail out otherwise */
322 SAC_DBG(SAC_DBG_INIT, "SAC PreloadGlobalMessageTable: No Messages.\n");
323 Status = STATUS_INVALID_PARAMETER;
324 goto Exit;
325 }
326
327 /* Allocate space for the buffers and headers */
328 GlobalMessageTable = SacAllocatePool(TotalLength, GLOBAL_BLOCK_TAG);
329 if (!GlobalMessageTable)
330 {
331 /* Bail out if we couldn't allocate it */
332 Status = STATUS_NO_MEMORY;
333 goto Exit;
334 }
335
336 /* All the buffers are going to be at the end of the table */
337 StringBuffer = (PWCHAR)(&GlobalMessageTable[GlobalMessageTableCount]);
338
339 /* Now loop over our entries again */
340 for (i = 0, MessageId = 1; MessageId != SAC_MAX_MESSAGES; MessageId++)
341 {
342 /* Make sure the message is still there! */
343 Status2 = RtlFindMessage(ImageBase,
344 RT_MESSAGETABLE,
345 MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
346 MessageId,
347 &MessageEntry);
348 if (NT_SUCCESS(Status2))
349 {
350 /* Write the entry in the message table*/
351 GlobalMessageTable[i].Index = MessageId;
352 GlobalMessageTable[i].Buffer = StringBuffer;
353
354 /* The structure includes the size of the header, elide it */
355 TextSize = MessageEntry->Length -
356 FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY, Text);
357
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);
361
362 /* Move to the next buffer space */
363 StringBuffer += (TextSize / sizeof(WCHAR));
364
365 /* Move to the next entry, make sure the status is full success */
366 i++;
367 Status = STATUS_SUCCESS;
368 }
369 }
370
371Exit:
372 /* All done, return the status code */
373 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC TearDownGlobalMessageTable: Exiting with status 0x%0x\n", Status);
374 return Status;
375}
376
377NTSTATUS
378NTAPI
379TearDownGlobalMessageTable(VOID)
380{
381 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC TearDownGlobalMessageTable: Entering.\n");
382
383 /* Free the table if one existed */
384 if (GlobalMessageTable) SacFreePool(GlobalMessageTable);
385
386 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC TearDownGlobalMessageTable: Exiting\n");
387 return STATUS_SUCCESS;
388}
389
390NTSTATUS
391NTAPI
392GetRegistryValueBuffer(IN PCWSTR KeyName,
393 IN PWCHAR ValueName,
394 IN PKEY_VALUE_PARTIAL_INFORMATION* Buffer)
395{
396 NTSTATUS Status;
397 OBJECT_ATTRIBUTES ObjectAttributes;
398 UNICODE_STRING DestinationString;
399 HANDLE Handle;
400 ULONG ResultLength = 0;
401 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: Entering.\n");
402 CHECK_PARAMETER1(KeyName);
403 CHECK_PARAMETER2(ValueName);
404
405 /* Open the specified key */
406 RtlInitUnicodeString(&DestinationString, KeyName);
407 InitializeObjectAttributes(&ObjectAttributes,
408 &DestinationString,
409 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
410 NULL,
411 NULL);
412 Status = ZwOpenKey(&Handle,
413 KEY_WRITE | SYNCHRONIZE | KEY_READ,
414 &ObjectAttributes);
415 if (!NT_SUCCESS(Status))
416 {
417 /* Bail out on failure */
418 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: failed ZwOpenKey: %X.\n", Status);
419 return Status;
420 }
421
422 /* Query the size of the key */
423 RtlInitUnicodeString(&DestinationString, ValueName);
424 Status = ZwQueryValueKey(Handle,
425 &DestinationString,
426 KeyValuePartialInformation,
427 NULL,
428 0,
429 &ResultLength);
430 if (!ResultLength)
431 goto Quit;
432
433 /* Allocate the buffer for the partial info structure and our integer data */
434 ResultLength += sizeof(ULONG);
435 *Buffer = SacAllocatePool(ResultLength, GLOBAL_BLOCK_TAG);
436 if (!*Buffer)
437 {
438 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: failed allocation\n");
439 goto Quit;
440 }
441
442 /* Now read the data */
443 Status = ZwQueryValueKey(Handle,
444 &DestinationString,
445 KeyValuePartialInformation,
446 *Buffer,
447 ResultLength,
448 &ResultLength);
449 if (!NT_SUCCESS(Status))
450 {
451 /* Free the buffer if we couldn't read the data */
452 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: failed ZwQueryValueKey: %X.\n", Status);
453 SacFreePool(*Buffer);
454 }
455
456Quit:
457 /* Close the handle and exit */
458 ZwClose(Handle);
459 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: Exiting.\n");
460 return Status;
461}
462
463NTSTATUS
464NTAPI
465SetRegistryValue(IN PCWSTR KeyName,
466 IN PWCHAR ValueName,
467 IN ULONG Type,
468 IN PVOID Data,
469 IN ULONG DataSize)
470{
471 NTSTATUS Status;
472 OBJECT_ATTRIBUTES ObjectAttributes;
473 UNICODE_STRING DestinationString;
474 HANDLE Handle;
475 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: Entering.\n");
476 CHECK_PARAMETER1(KeyName);
477 CHECK_PARAMETER2(ValueName);
478 CHECK_PARAMETER4(Data);
479
480 /* Open the specified key */
481 RtlInitUnicodeString(&DestinationString, KeyName);
482 InitializeObjectAttributes(&ObjectAttributes,
483 &DestinationString,
484 OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
485 NULL,
486 NULL);
487 Status = ZwOpenKey(&Handle,
488 KEY_WRITE | SYNCHRONIZE | KEY_READ,
489 &ObjectAttributes);
490 if (!NT_SUCCESS(Status))
491 {
492 /* Bail out on failure */
493 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: failed ZwOpenKey: %X.\n", Status);
494 return Status;
495 }
496
497 /* Set the specified value */
498 RtlInitUnicodeString(&DestinationString, ValueName);
499 Status = ZwSetValueKey(Handle, &DestinationString, 0, Type, Data, DataSize);
500 if (!NT_SUCCESS(Status))
501 {
502 /* Print error on failure */
503 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: failed ZwSetValueKey: %X.\n", Status);
504 }
505
506 /* Close the handle and exit */
507 ZwClose(Handle);
508 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: Exiting.\n");
509 return Status;
510}
511
512NTSTATUS
513NTAPI
514CopyRegistryValueData(IN PVOID* Buffer,
515 IN PKEY_VALUE_PARTIAL_INFORMATION PartialInfo)
516{
517 NTSTATUS Status = STATUS_SUCCESS;
518 CHECK_PARAMETER1(Buffer);
519 CHECK_PARAMETER2(PartialInfo);
520
521 /* Allocate space for registry data */
522 *Buffer = SacAllocatePool(PartialInfo->DataLength, GLOBAL_BLOCK_TAG);
523 if (*Buffer)
524 {
525 /* Copy the data into the buffer */
526 RtlCopyMemory(*Buffer, PartialInfo->Data, PartialInfo->DataLength);
527 }
528 else
529 {
530 /* Set the correct error code */
531 SAC_DBG(SAC_DBG_UTIL, "SAC CopyRegistryValueBuffer: Failed ALLOCATE.\n");
532 Status = STATUS_NO_MEMORY;
533 }
534
535 /* Return the result */
536 return Status;
537}
538
539NTSTATUS
540NTAPI
541TranslateMachineInformationXML(IN PWCHAR *Buffer,
542 IN PWCHAR ExtraData)
543{
544 NTSTATUS Status;
545 SIZE_T Size;
546 PWCHAR p;
547 CHECK_PARAMETER1(Buffer);
548
549 /* Start by believing the world is beautiful */
550 Status = STATUS_SUCCESS;
551
552 /* First, the header */
553 Size = wcslen(L"<machine-info>\r\n");
554
555 /* Do we have a machine name? */
556 if (MachineInformation->MachineName)
557 {
558 /* Go and add it in */
559 Size += wcslen(MachineInformation->MachineName);
560 Size += wcslen(L"<name>%s</name>\r\n");
561 }
562
563 /* Do we have a GUID? */
564 if (MachineInformation->MachineGuid)
565 {
566 /* Go and add it in */
567 Size += wcslen(MachineInformation->MachineGuid);
568 Size += wcslen(L"<guid>%s</guid>\r\n");
569 }
570
571 /* Do we know the processor? */
572 if (MachineInformation->ProcessorArchitecture)
573 {
574 /* Go and add it in */
575 Size += wcslen(MachineInformation->ProcessorArchitecture);
576 Size += wcslen(L"<processor-architecture>%s</processor-architecture>\r\n");
577 }
578
579 /* Do we have the version? */
580 if (MachineInformation->MajorVersion)
581 {
582 /* Go and add it in */
583 Size += wcslen(MachineInformation->MajorVersion);
584 Size += wcslen(L"<os-version>%s</os-version>\r\n");
585 }
586
587 /* Do we have the build? */
588 if (MachineInformation->BuildNumber)
589 {
590 /* Go and add it in */
591 Size += wcslen(MachineInformation->BuildNumber);
592 Size += wcslen(L"<os-build-number>%s</os-build-number>\r\n");
593 }
594
595 /* Do we have the product type? */
596 if (MachineInformation->ProductType)
597 {
598 /* Go and add it in */
599 Size += wcslen(MachineInformation->ProductType);
600 Size += wcslen(L"<os-product>%s</os-product>\r\n");
601 }
602
603 /* Do we have a service pack? */
604 if (MachineInformation->ServicePack)
605 {
606 /* Go and add it in */
607 Size += wcslen(MachineInformation->ServicePack);
608 Size += wcslen(L"<os-service-pack>%s</os-service-pack>\r\n");
609 }
610
611 /* Anything else we need to know? Add it in too */
612 if (ExtraData) Size += wcslen(ExtraData);
613
614 /* Finally, add the footer */
615 Size += wcslen(L"</machine-info>\r\n");
616
617 /* Convert to bytes and add a NULL */
618 Size += sizeof(ANSI_NULL);
619 Size *= sizeof(WCHAR);
620
621 /* Allocate space for the buffer */
622 p = SacAllocatePool(Size, GLOBAL_BLOCK_TAG);
623 *Buffer = p;
624 if (!p) return STATUS_NO_MEMORY;
625
626 wcscpy(p, L"<machine-info>\r\n");
627 p += wcslen(L"<machine-info>\r\n");
628
629 if (MachineInformation->MachineName)
630 {
631 p += swprintf(p,
632 L"<name>%s</name>\r\n",
633 MachineInformation->MachineName);
634 }
635
636 if (MachineInformation->MachineGuid)
637 {
638 p += swprintf(p,
639 L"<guid>%s</guid>\r\n",
640 MachineInformation->MachineGuid);
641 }
642
643 if (MachineInformation->ProcessorArchitecture)
644 {
645 p += swprintf(p,
646 L"<processor-architecture>%s</processor-architecture>\r\n",
647 MachineInformation->ProcessorArchitecture);
648 }
649
650 if (MachineInformation->MajorVersion)
651 {
652 p += swprintf(p,
653 L"<os-version>%s</os-version>\r\n",
654 MachineInformation->MajorVersion);
655 }
656
657 if (MachineInformation->BuildNumber)
658 {
659 p += swprintf(p,
660 L"<os-build-number>%s</os-build-number>\r\n",
661 MachineInformation->BuildNumber);
662 }
663
664 if (MachineInformation->ProductType)
665 {
666 p += swprintf(p,
667 L"<os-product>%s</os-product>\r\n",
668 MachineInformation->ProductType);
669 }
670
671 if (MachineInformation->ServicePack)
672 {
673 p += swprintf(p,
674 L"<os-service-pack>%s</os-service-pack>\r\n",
675 MachineInformation->ServicePack);
676 }
677
678 if (ExtraData)
679 {
680 wcscpy(p, ExtraData);
681 p += wcslen(ExtraData);
682 }
683
684 wcscpy(p, L"</machine-info>\r\n");
685 SAC_DBG(SAC_DBG_ENTRY_EXIT, "MachineInformation: %S\n", *Buffer);
686 ASSERT((((ULONG)wcslen(*Buffer) + 1) * sizeof(WCHAR)) <= Size);
687 return Status;
688}
689
690VOID
691NTAPI
692InitializeMachineInformation(VOID)
693{
694 NTSTATUS Status;
695 PWCHAR GuidString, MajorVersion, ServicePack, BuildNumber, MessageBuffer;
696 PWCHAR ProductType;
697 ULONG SuiteTypeMessage;
698 BOOLEAN SetupInProgress = FALSE;
699 GUID SystemGuid;
700 SIZE_T RealSize, Size, OutputSize;
701 PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
702 RTL_OSVERSIONINFOEXW VersionInformation;
703 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC Initialize Machine Information : Entering.\n");
704
705 /* Don't do anything if we already queried this */
706 if (MachineInformation)
707 {
708 SAC_DBG(SAC_DBG_MACHINE, "SAC Initialize Machine Information:: MachineInformationBuffer already initialized.\n");
709 return;
710 }
711
712 /* Allocate the machine information */
713 MachineInformation = SacAllocatePool(sizeof(*MachineInformation),
714 GLOBAL_BLOCK_TAG);
715 if (!MachineInformation)
716 {
717 goto Fail;
718 }
719
720 /* Zero it out for now */
721 RtlZeroMemory(MachineInformation, sizeof(*MachineInformation));
722
723 /* Query OS version */
724 RtlZeroMemory(&VersionInformation, sizeof(VersionInformation));
725 VersionInformation.dwOSVersionInfoSize = sizeof(VersionInformation);
726 Status = RtlGetVersion((PRTL_OSVERSIONINFOW)&VersionInformation);
727 if (!NT_SUCCESS(Status))
728 {
729 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (2).\n");
730 goto Fail;
731 }
732
733 /* Check if setup is in progress */
734 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\Setup",
735 L"SystemSetupInProgress",
736 &PartialInfo);
737 if (NT_SUCCESS(Status))
738 {
739 /* The key is there, is the value set? */
740 if (*(PULONG)PartialInfo->Data) SetupInProgress = TRUE;
741 SacFreePool(PartialInfo);
742 if (SetupInProgress)
743 {
744 /* Yes, so we'll use a special hostname to identify this */
745 MessageBuffer = GetMessage(SAC_UNINITIALIZED_MSG);
746 Size = wcslen(MessageBuffer);
747 ASSERT(Size > 0);
748 RealSize = Size * sizeof(WCHAR) + sizeof(UNICODE_NULL);
749
750 /* Make room for it and copy it in there */
751 MachineInformation->MachineName = SacAllocatePool(RealSize,
752 GLOBAL_BLOCK_TAG);
753 if (MachineInformation->MachineName)
754 {
755 wcscpy(MachineInformation->MachineName, MessageBuffer);
756 }
757 }
758 }
759
760 /* If we are not in setup mode, or if we failed to check... */
761 if (!SetupInProgress)
762 {
763 /* Query the computer name */
764 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\"
765 L"CurrentControlSet\\Control\\"
766 L"ComputerName\\ComputerName",
767 L"ComputerName",
768 &PartialInfo);
769 if (!NT_SUCCESS(Status))
770 {
771 /* It's not critical, but we won't have it */
772 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Failed to get machine name.\n");
773 }
774 else
775 {
776 /* We have the name, copy it from the registry */
777 Status = CopyRegistryValueData((PVOID*)&MachineInformation->
778 MachineName,
779 PartialInfo);
780 SacFreePool(PartialInfo);
781 if (!NT_SUCCESS(Status))
782 {
783 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (20).\n");
784 goto Fail;
785 }
786 }
787 }
788
789 /* Next step, try to get the machine GUID */
790 RtlZeroMemory(&SystemGuid, sizeof(SystemGuid));
791 OutputSize = sizeof(SystemGuid);
792 Status = HeadlessDispatch(HeadlessCmdQueryGUID,
793 NULL,
794 0,
795 &SystemGuid,
796 &OutputSize);
797 if (!NT_SUCCESS(Status))
798 {
799 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Failed to get Machine GUID.\n");
800 }
801 else
802 {
803 /* We have it -- make room for it */
804 GuidString = SacAllocatePool(0x50, GLOBAL_BLOCK_TAG);
805 if (!GuidString)
806 {
807 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (31).\n");
808 goto Fail;
809 }
810
811 /* Build the string with the GUID in it, and save the ppointer to it */
812 swprintf(GuidString,
813 L"%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
814 SystemGuid.Data1,
815 SystemGuid.Data2,
816 SystemGuid.Data3,
817 SystemGuid.Data4[0],
818 SystemGuid.Data4[1],
819 SystemGuid.Data4[2],
820 SystemGuid.Data4[3],
821 SystemGuid.Data4[4],
822 SystemGuid.Data4[5],
823 SystemGuid.Data4[6],
824 SystemGuid.Data4[7]);
825 MachineInformation->MachineGuid = GuidString;
826 }
827
828 /* Next, query the processor architecture */
829 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\"
830 L"CurrentControlSet\\Control\\"
831 L"Session Manager\\Environment",
832 L"PROCESSOR_ARCHITECTURE",
833 &PartialInfo);
834 if (!NT_SUCCESS(Status))
835 {
836 /* It's not critical, but we won't have it */
837 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (30).\n");
838 }
839 else
840 {
841 /* We have it! Copy the value from the registry */
842 Status = CopyRegistryValueData((PVOID*)&MachineInformation->
843 ProcessorArchitecture,
844 PartialInfo);
845 SacFreePool(PartialInfo);
846 if (!NT_SUCCESS(Status))
847 {
848 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (30).\n");
849 goto Fail;
850 }
851 }
852
853 /* Now allocate a buffer for the OS version number */
854 MajorVersion = SacAllocatePool(0x18, GLOBAL_BLOCK_TAG);
855 if (!MajorVersion)
856 {
857 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (50).\n");
858 goto Fail;
859 }
860
861 /* Build the buffer and set a pointer to it */
862 swprintf(MajorVersion,
863 L"%d.%d",
864 VersionInformation.dwMajorVersion,
865 VersionInformation.dwMinorVersion);
866 MachineInformation->MajorVersion = MajorVersion;
867
868 /* Now allocate a buffer for the OS build number */
869 BuildNumber = SacAllocatePool(0xC, GLOBAL_BLOCK_TAG);
870 if (!BuildNumber)
871 {
872 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (60).\n");
873 goto Fail;
874 }
875
876 /* Build the buffer and set a pointer to it */
877 swprintf(BuildNumber, L"%d", VersionInformation.dwBuildNumber);
878 MachineInformation->BuildNumber = BuildNumber;
879
880 /* Now check what kind of SKU this is */
881 if (ExVerifySuite(DataCenter))
882 {
883 SuiteTypeMessage = SAC_DATACENTER_SUITE_MSG;
884 }
885 else if (ExVerifySuite(EmbeddedNT))
886 {
887 SuiteTypeMessage = SAC_EMBEDDED_SUITE_MSG;
888 }
889 else if (ExVerifySuite(Enterprise))
890 {
891 SuiteTypeMessage = SAC_ENTERPRISE_SUITE_MSG;
892 }
893 else
894 {
895 /* Unknown or perhaps a client SKU */
896 SuiteTypeMessage = SAC_NO_SUITE_MSG;
897 }
898
899 /* Get the string that corresponds to the SKU type */
900 MessageBuffer = GetMessage(SuiteTypeMessage);
901 if (!MessageBuffer)
902 {
903 /* We won't have it, but this isn't critical */
904 SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed to get product type.\n");
905 }
906 else
907 {
908 /* Calculate the size we need to hold the string */
909 Size = wcslen(MessageBuffer);
910 ASSERT(Size > 0);
911 RealSize = Size * sizeof(WCHAR) + sizeof(UNICODE_NULL);
912
913 /* Allocate a buffer for it */
914 ProductType = SacAllocatePool(RealSize, GLOBAL_BLOCK_TAG);
915 if (!ProductType)
916 {
917 SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed product type memory allocation.\n");
918 goto Fail;
919 }
920
921 /* Copy the string and set the pointer */
922 RtlCopyMemory(ProductType, MessageBuffer, RealSize);
923 MachineInformation->ProductType = ProductType;
924 }
925
926 /* Check if this is a SP version or RTM version */
927 if (VersionInformation.wServicePackMajor)
928 {
929 /* This is a service pack, allocate a buffer for the version */
930 ServicePack = SacAllocatePool(0x18, GLOBAL_BLOCK_TAG);
931 if (ServicePack)
932 {
933 /* Build the buffer and set a pointer to it */
934 swprintf(ServicePack,
935 L"%d.%d",
936 VersionInformation.wServicePackMajor,
937 VersionInformation.wServicePackMinor);
938 MachineInformation->ServicePack = ServicePack;
939
940 /* We've collected all the machine info and are done! */
941 return;
942 }
943
944 /* This is the failure path */
945 SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed service pack memory allocation.\n");
946 }
947 else
948 {
949 /* Get a generic string that indicates there's no service pack */
950 MessageBuffer = GetMessage(SAC_NO_DATA_MSG);
951 Size = wcslen(MessageBuffer);
952 ASSERT(Size > 0);
953 RealSize = Size * sizeof(WCHAR) + sizeof(UNICODE_NULL);
954
955 /* Allocate memory for the "no service pack" string */
956 ServicePack = SacAllocatePool(RealSize, GLOBAL_BLOCK_TAG);
957 if (ServicePack)
958 {
959 /* Copy the buffer and set a pointer to it */
960 RtlCopyMemory(ServicePack, MessageBuffer, RealSize);
961 MachineInformation->ServicePack = ServicePack;
962
963 /* We've collected all the machine info and are done! */
964 return;
965 }
966
967 SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed service pack memory allocation.\n");
968 }
969
970Fail:
971 /* In the failure path, always cleanup the machine information buffer */
972 if (MachineInformation)
973 {
974 SacFreePool(MachineInformation);
975 }
976 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC Initialize Machine Information : Exiting with error.\n");
977}
978
979NTSTATUS
980NTAPI
981GetCommandConsoleLaunchingPermission(OUT PBOOLEAN Permission)
982{
983 NTSTATUS Status;
984 PKEY_VALUE_PARTIAL_INFORMATION Dummy;
985
986 /* Assume success and read the key */
987 *Permission = TRUE;
988 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacdrv",
989 L"DisableCmdSessions",
990 &Dummy);
991 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
992 {
993 /* The default is success */
994 Status = STATUS_SUCCESS;
995 }
996 else
997 {
998 /* Only if the key is present and set, do we disable permission */
999 if (NT_SUCCESS(Status)) *Permission = FALSE;
1000 }
1001
1002 /* Return status */
1003 return Status;
1004}
1005
1006NTSTATUS
1007NTAPI
1008ImposeSacCmdServiceStartTypePolicy(VOID)
1009{
1010 NTSTATUS Status;
1011 PKEY_VALUE_PARTIAL_INFORMATION Buffer = NULL;
1012 PULONG Data;
1013
1014 /* Read the service start type*/
1015 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacsvr",
1016 L"Start",
1017 &Buffer);
1018 if (!NT_SUCCESS(Status)) return Status;
1019
1020 /* If there's no start type, fail, as this is unusual */
1021 if (!Buffer) return STATUS_UNSUCCESSFUL;
1022
1023 /* Read the value */
1024 Status = CopyRegistryValueData((PVOID*)&Data, Buffer);
1025 SacFreePool(Buffer);
1026 if (!NT_SUCCESS(Status)) return Status;
1027
1028 /* Check what the current start type is */
1029 switch (*Data)
1030 {
1031 /* It's boot, system, or disabled */
1032 case 1:
1033 case 2:
1034 case 4:
1035 /* Leave it as is */
1036 return Status;
1037
1038 case 3:
1039
1040 /* It's set to automatic, set it to system instead */
1041 *Data = 2;
1042 Status = SetRegistryValue(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacsvr",
1043 L"Start",
1044 REG_DWORD,
1045 Data,
1046 sizeof(ULONG));
1047 if (!NT_SUCCESS(Status))
1048 {
1049 SAC_DBG(SAC_DBG_INIT, "SAC ImposeSacCmdServiceStartTypePolicy: Failed SetRegistryValue: %X\n", Status);
1050 }
1051 break;
1052
1053 default:
1054 ASSERT(FALSE);
1055 }
1056
1057 return Status;
1058}
1059
1060VOID
1061NTAPI
1062InitializeCmdEventInfo(VOID)
1063{
1064 /* Check if we were already initialized */
1065 if (HaveUserModeServiceCmdEventInfo)
1066 {
1067 /* Full state expected */
1068 ASSERT(RequestSacCmdEventObjectBody);
1069 ASSERT(RequestSacCmdSuccessEventObjectBody);
1070 ASSERT(RequestSacCmdFailureEventObjectBody);
1071
1072 /* Dereference each wait object in turn */
1073 if (RequestSacCmdEventObjectBody)
1074 {
1075 ObDereferenceObject(RequestSacCmdEventObjectBody);
1076 }
1077
1078 if (RequestSacCmdSuccessEventObjectBody)
1079 {
1080 ObDereferenceObject(RequestSacCmdSuccessEventObjectBody);
1081 }
1082
1083 if (RequestSacCmdFailureEventObjectBody)
1084 {
1085 ObDereferenceObject(RequestSacCmdFailureEventObjectBody);
1086 }
1087 }
1088
1089 /* Claer everything */
1090 RequestSacCmdEventObjectBody = NULL;
1091 RequestSacCmdEventWaitObjectBody = NULL;
1092 RequestSacCmdSuccessEventObjectBody = NULL;
1093 RequestSacCmdSuccessEventWaitObjectBody = NULL;
1094 RequestSacCmdFailureEventObjectBody = NULL;
1095 RequestSacCmdFailureEventWaitObjectBody = NULL;
1096 ServiceProcessFileObject = NULL;
1097
1098 /* Reset state */
1099 HaveUserModeServiceCmdEventInfo = FALSE;
1100}
1101
1102NTSTATUS
1103NTAPI
1104RegisterBlueScreenMachineInformation(VOID)
1105{
1106 PWCHAR XmlBuffer;
1107 PHEADLESS_CMD_SET_BLUE_SCREEN_DATA BsBuffer;
1108 SIZE_T Length, HeaderLength, TotalLength;
1109 NTSTATUS Status;
1110 ULONG i;
1111
1112 /* Create the XML buffer and make sure it's OK */
1113 Status = TranslateMachineInformationXML(&XmlBuffer, NULL);
1114 CHECK_PARAMETER_WITH_STATUS(NT_SUCCESS(Status), Status);
1115 CHECK_PARAMETER_WITH_STATUS(XmlBuffer, STATUS_UNSUCCESSFUL);
1116
1117 /* Compute the sizes and allocate a buffer for it */
1118 Length = wcslen(XmlBuffer);
1119 HeaderLength = strlen("MACHINEINFO");
1120 TotalLength = HeaderLength +
1121 Length +
1122 sizeof(*BsBuffer) +
1123 2 * sizeof(ANSI_NULL);
1124 BsBuffer = SacAllocatePool(TotalLength, GLOBAL_BLOCK_TAG);
1125 CHECK_PARAMETER_WITH_STATUS(BsBuffer, STATUS_NO_MEMORY);
1126
1127 /* Copy the XML property name */
1128 strcpy((PCHAR)BsBuffer->Data, "MACHINEINFO");
1129 BsBuffer->ValueIndex = HeaderLength + sizeof(ANSI_NULL);
1130
1131 /* Copy the data and NULL-terminate it */
1132 for (i = 0; i < Length; i++)
1133 {
1134 BsBuffer->Data[BsBuffer->ValueIndex + i] = XmlBuffer[i];
1135 }
1136 BsBuffer->Data[BsBuffer->ValueIndex + i] = ANSI_NULL;
1137
1138 /* Let the OS save the buffer for later */
1139 Status = HeadlessDispatch(HeadlessCmdSetBlueScreenData,
1140 BsBuffer,
1141 TotalLength,
1142 NULL,
1143 NULL);
1144
1145 /* Failure or not, we don't need this anymore */
1146 SacFreePool(BsBuffer);
1147 SacFreePool(XmlBuffer);
1148
1149 /* Return the result */
1150 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC Initialize Machine Information: Exiting.\n");
1151 return Status;
1152}
1153
1154VOID
1155NTAPI
1156FreeMachineInformation(VOID)
1157{
1158 ASSERT(MachineInformation);
1159
1160 /* Free every cached string of machine information */
1161 if (MachineInformation->MachineName) SacFreePool(MachineInformation);
1162 if (MachineInformation->MachineGuid) SacFreePool(MachineInformation->MachineGuid);
1163 if (MachineInformation->ProcessorArchitecture) SacFreePool(MachineInformation->ProcessorArchitecture);
1164 if (MachineInformation->MajorVersion) SacFreePool(MachineInformation->MajorVersion);
1165 if (MachineInformation->BuildNumber) SacFreePool(MachineInformation->BuildNumber);
1166 if (MachineInformation->ProductType) SacFreePool(MachineInformation->ProductType);
1167 if (MachineInformation->ServicePack) SacFreePool(MachineInformation->ServicePack);
1168}
1169
1170BOOLEAN
1171NTAPI
1172VerifyEventWaitable(IN HANDLE Handle,
1173 OUT PVOID *WaitObject,
1174 OUT PVOID *ActualWaitObject)
1175{
1176 PVOID Object;
1177 NTSTATUS Status;
1178 POBJECT_TYPE ObjectType;
1179
1180 /* Reference the object */
1181 Status = ObReferenceObjectByHandle(Handle,
1182 EVENT_ALL_ACCESS,
1183 NULL,
1184 KernelMode,
1185 &Object,
1186 NULL);
1187 *WaitObject = Object;
1188 if (!NT_SUCCESS(Status))
1189 {
1190 SAC_DBG(SAC_DBG_INIT, "SAC VerifyEventWaitable: Unable to reference event object (%lx)\n", Status);
1191 return FALSE;
1192 }
1193
1194 /* Check if the object itself is NOT being used */
1195 ObjectType = OBJECT_TO_OBJECT_HEADER(Object)->Type;
1196 if (ObjectType->TypeInfo.UseDefaultObject == FALSE)
1197 {
1198 /* Get the actual object that's being used for the wait */
1199 *ActualWaitObject = (PVOID)((ULONG_PTR)Object +
1200 (ULONG_PTR)ObjectType->DefaultObject);
1201 return TRUE;
1202 }
1203
1204 /* Drop the reference we took */
1205 SAC_DBG(SAC_DBG_INIT, "SAC VerifyEventWaitable: event object not waitable!\n");
1206 ObDereferenceObject(*WaitObject);
1207 return FALSE;
1208}
1209
1210NTSTATUS
1211NTAPI
1212SerialBufferGetChar(OUT PCHAR Char)
1213{
1214 /* Check if nothing's been produced yet */
1215 if (SerialPortConsumerIndex == SerialPortProducerIndex)
1216 {
1217 return STATUS_NO_DATA_DETECTED;
1218 }
1219
1220 /* Consume the produced character and clear it*/
1221 *Char = SerialPortBuffer[SerialPortConsumerIndex];
1222 SerialPortBuffer[SerialPortConsumerIndex] = ANSI_NULL;
1223
1224 /* Advance the index and return success */
1225 _InterlockedExchange(&SerialPortConsumerIndex,
1226 (SerialPortConsumerIndex + 1) &
1227 (SAC_SERIAL_PORT_BUFFER_SIZE - 1));
1228 return STATUS_SUCCESS;
1229}
1230
1231ULONG
1232NTAPI
1233GetMessageLineCount(IN ULONG MessageIndex)
1234{
1235 ULONG LineCount = 0;
1236 PWCHAR Buffer;
1237
1238 /* Get the message buffer */
1239 Buffer = GetMessage(MessageIndex);
1240 if (Buffer)
1241 {
1242 /* Scan it looking for new lines, and increment the count each time */
1243 while (*Buffer) if (*Buffer++ == L'\n') ++LineCount;
1244 }
1245
1246 /* Return the line count */
1247 return LineCount;
1248}
1249
1250ULONG
1251ConvertAnsiToUnicode(
1252 IN PWCHAR pwch,
1253 IN PCHAR pch,
1254 IN ULONG length
1255 )
1256{
1257 return STATUS_NOT_IMPLEMENTED;
1258}
1259
1260BOOLEAN
1261IsCmdEventRegistrationProcess(
1262 IN PFILE_OBJECT FileObject
1263 )
1264{
1265 return FALSE;
1266}
1267
1268NTSTATUS
1269InvokeUserModeService(
1270 VOID
1271 )
1272{
1273 return STATUS_NOT_IMPLEMENTED;
1274}
1275
1276NTSTATUS
1277TranslateMachineInformationText(
1278 IN PWCHAR Buffer)
1279{
1280 return STATUS_NOT_IMPLEMENTED;
1281}
1282
1283NTSTATUS
1284CopyAndInsertStringAtInterval(
1285 IN PWCHAR SourceStr,
1286 IN ULONG Interval,
1287 IN PWCHAR InsertStr,
1288 OUT PWCHAR pDestStr
1289 )
1290{
1291 return STATUS_NOT_IMPLEMENTED;
1292}
1293
1294NTSTATUS
1295RegisterSacCmdEvent(
1296 IN PVOID Object,
1297 IN PKEVENT SetupCmdEvent[]
1298 )
1299{
1300 return STATUS_NOT_IMPLEMENTED;
1301}
1302
1303NTSTATUS
1304UnregisterSacCmdEvent(
1305 IN PFILE_OBJECT FileObject
1306 )
1307{
1308 return STATUS_NOT_IMPLEMENTED;
1309}