[MMIXER] Fix additional data size initialization for different audio formats (#6753)
[reactos.git] / drivers / sac / driver / util.c
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
17 PCHAR Utf8ConversionBuffer;
18 ULONG Utf8ConversionBufferSize = PAGE_SIZE;
19
20 PSAC_MACHINE_INFO MachineInformation;
21
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;
30
31 PSAC_MESSAGE_ENTRY GlobalMessageTable;
32 ULONG GlobalMessageTableCount;
33
34 LONG SerialPortConsumerIndex, SerialPortProducerIndex;
35 PCHAR SerialPortBuffer;
36
37 /* FUNCTIONS ******************************************************************/
38
39 BOOLEAN
40 NTAPI
41 SacTranslateUtf8ToUnicode(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
89 BOOLEAN
90 NTAPI
91 SacTranslateUnicodeToUtf8(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
137 PWCHAR
138 NTAPI
139 GetMessage(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
163 NTSTATUS
164 NTAPI
165 UTF8EncodeAndSend(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
200 VOID
201 NTAPI
202 SacFormatMessage(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
278 NTSTATUS
279 NTAPI
280 PreloadGlobalMessageTable(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 ID in the string table*/
298 Status2 = RtlFindMessage(ImageBase,
299 11,
300 LANG_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 11,
345 LANG_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
371 Exit:
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
377 NTSTATUS
378 NTAPI
379 TearDownGlobalMessageTable(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
390 NTSTATUS
391 NTAPI
392 GetRegistryValueBuffer(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,
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) return Status;
431
432 /* Allocate the buffer for the partial info structure and our integer data */
433 ResultLength += sizeof(ULONG);
434 *Buffer = SacAllocatePool(ResultLength, GLOBAL_BLOCK_TAG);
435 if (!*Buffer)
436 {
437 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: failed allocation\n");
438 return Status;
439 }
440
441 /* Now read the data */
442 Status = ZwQueryValueKey(Handle,
443 &DestinationString,
444 KeyValuePartialInformation,
445 *Buffer,
446 ResultLength,
447 &ResultLength);
448 if (!NT_SUCCESS(Status))
449 {
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);
453 }
454
455 /* Return the result */
456 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: Exiting.\n");
457 return Status;
458 }
459
460 NTSTATUS
461 NTAPI
462 SetRegistryValue(IN PCWSTR KeyName,
463 IN PWCHAR ValueName,
464 IN ULONG Type,
465 IN PVOID Data,
466 IN ULONG DataSize)
467 {
468 NTSTATUS Status;
469 OBJECT_ATTRIBUTES ObjectAttributes;
470 UNICODE_STRING DestinationString;
471 HANDLE Handle;
472 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: Entering.\n");
473 CHECK_PARAMETER1(KeyName);
474 CHECK_PARAMETER2(ValueName);
475 CHECK_PARAMETER4(Data);
476
477 /* Open the specified key */
478 RtlInitUnicodeString(&DestinationString, KeyName);
479 InitializeObjectAttributes(&ObjectAttributes,
480 &DestinationString,
481 OBJ_CASE_INSENSITIVE,
482 NULL,
483 NULL);
484 Status = ZwOpenKey(&Handle,
485 KEY_WRITE | SYNCHRONIZE | KEY_READ,
486 &ObjectAttributes);
487 if (!NT_SUCCESS(Status))
488 {
489 /* Bail out on failure */
490 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: failed ZwOpenKey: %X.\n", Status);
491 return Status;
492 }
493
494 /* Set the specified value */
495 RtlInitUnicodeString(&DestinationString, ValueName);
496 Status = ZwSetValueKey(Handle, &DestinationString, 0, Type, Data, DataSize);
497 if (!NT_SUCCESS(Status))
498 {
499 /* Print error on failure */
500 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: failed ZwSetValueKey: %X.\n", Status);
501 }
502
503 /* Close the handle and exit */
504 NtClose(Handle);
505 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: Exiting.\n");
506 return Status;
507 }
508
509 NTSTATUS
510 NTAPI
511 CopyRegistryValueData(IN PVOID* Buffer,
512 IN PKEY_VALUE_PARTIAL_INFORMATION PartialInfo)
513 {
514 NTSTATUS Status = STATUS_SUCCESS;
515 CHECK_PARAMETER1(Buffer);
516 CHECK_PARAMETER2(PartialInfo);
517
518 /* Allocate space for registry data */
519 *Buffer = SacAllocatePool(PartialInfo->DataLength, GLOBAL_BLOCK_TAG);
520 if (*Buffer)
521 {
522 /* Copy the data into the buffer */
523 RtlCopyMemory(*Buffer, PartialInfo->Data, PartialInfo->DataLength);
524 }
525 else
526 {
527 /* Set the correct error code */
528 SAC_DBG(SAC_DBG_UTIL, "SAC CopyRegistryValueBuffer: Failed ALLOCATE.\n");
529 Status = STATUS_NO_MEMORY;
530 }
531
532 /* Return the result */
533 return Status;
534 }
535
536 NTSTATUS
537 NTAPI
538 TranslateMachineInformationXML(IN PWCHAR *Buffer,
539 IN PWCHAR ExtraData)
540 {
541 NTSTATUS Status;
542 SIZE_T Size;
543 PWCHAR p;
544 CHECK_PARAMETER1(Buffer);
545
546 /* Start by believing the world is beautiful */
547 Status = STATUS_SUCCESS;
548
549 /* First, the header */
550 Size = wcslen(L"<machine-info>\r\n");
551
552 /* Do we have a machine name? */
553 if (MachineInformation->MachineName)
554 {
555 /* Go and add it in */
556 Size += wcslen(MachineInformation->MachineName);
557 Size += wcslen(L"<name>%s</name>\r\n");
558 }
559
560 /* Do we have a GUID? */
561 if (MachineInformation->MachineGuid)
562 {
563 /* Go and add it in */
564 Size += wcslen(MachineInformation->MachineGuid);
565 Size += wcslen(L"<guid>%s</guid>\r\n");
566 }
567
568 /* Do we know the processor? */
569 if (MachineInformation->ProcessorArchitecture)
570 {
571 /* Go and add it in */
572 Size += wcslen(MachineInformation->ProcessorArchitecture);
573 Size += wcslen(L"<processor-architecture>%s</processor-architecture>\r\n");
574 }
575
576 /* Do we have the version? */
577 if (MachineInformation->MajorVersion)
578 {
579 /* Go and add it in */
580 Size += wcslen(MachineInformation->MajorVersion);
581 Size += wcslen(L"<os-version>%s</os-version>\r\n");
582 }
583
584 /* Do we have the build? */
585 if (MachineInformation->BuildNumber)
586 {
587 /* Go and add it in */
588 Size += wcslen(MachineInformation->BuildNumber);
589 Size += wcslen(L"<os-build-number>%s</os-build-number>\r\n");
590 }
591
592 /* Do we have the product type? */
593 if (MachineInformation->ProductType)
594 {
595 /* Go and add it in */
596 Size += wcslen(MachineInformation->ProductType);
597 Size += wcslen(L"<os-product>%s</os-product>\r\n");
598 }
599
600 /* Do we have a service pack? */
601 if (MachineInformation->ServicePack)
602 {
603 /* Go and add it in */
604 Size += wcslen(MachineInformation->ServicePack);
605 Size += wcslen(L"<os-service-pack>%s</os-service-pack>\r\n");
606 }
607
608 /* Anything else we need to know? Add it in too */
609 if (ExtraData) Size += wcslen(ExtraData);
610
611 /* Finally, add the footer */
612 Size += wcslen(L"</machine-info>\r\n");
613
614 /* Convert to bytes and add a NULL */
615 Size += sizeof(ANSI_NULL);
616 Size *= sizeof(WCHAR);
617
618 /* Allocate space for the buffer */
619 p = SacAllocatePool(Size, GLOBAL_BLOCK_TAG);
620 *Buffer = p;
621 if (!p) return STATUS_NO_MEMORY;
622
623 wcscpy(p, L"<machine-info>\r\n");
624 p += wcslen(L"<machine-info>\r\n");
625
626 if (MachineInformation->MachineName)
627 {
628 p += swprintf(p,
629 L"<name>%s</name>\r\n",
630 MachineInformation->MachineName);
631 }
632
633 if (MachineInformation->MachineGuid)
634 {
635 p += swprintf(p,
636 L"<guid>%s</guid>\r\n",
637 MachineInformation->MachineGuid);
638 }
639
640 if (MachineInformation->ProcessorArchitecture)
641 {
642 p += swprintf(p,
643 L"<processor-architecture>%s</processor-architecture>\r\n",
644 MachineInformation->ProcessorArchitecture);
645 }
646
647 if (MachineInformation->MajorVersion)
648 {
649 p += swprintf(p,
650 L"<os-version>%s</os-version>\r\n",
651 MachineInformation->MajorVersion);
652 }
653
654 if (MachineInformation->BuildNumber)
655 {
656 p += swprintf(p,
657 L"<os-build-number>%s</os-build-number>\r\n",
658 MachineInformation->BuildNumber);
659 }
660
661 if (MachineInformation->ProductType)
662 {
663 p += swprintf(p,
664 L"<os-product>%s</os-product>\r\n",
665 MachineInformation->ProductType);
666 }
667
668 if (MachineInformation->ServicePack)
669 {
670 p += swprintf(p,
671 L"<os-service-pack>%s</os-service-pack>\r\n",
672 MachineInformation->ServicePack);
673 }
674
675 if (ExtraData)
676 {
677 wcscpy(p, ExtraData);
678 p += wcslen(ExtraData);
679 }
680
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);
684 return Status;
685 }
686
687 VOID
688 NTAPI
689 InitializeMachineInformation(VOID)
690 {
691 NTSTATUS Status;
692 PWCHAR GuidString, MajorVersion, ServicePack, BuildNumber, MessageBuffer;
693 PWCHAR ProductType;
694 ULONG SuiteTypeMessage;
695 BOOLEAN SetupInProgress = FALSE;
696 GUID SystemGuid;
697 SIZE_T 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");
701
702 /* Don't do anything if we already queried this */
703 if (MachineInformation)
704 {
705 SAC_DBG(SAC_DBG_MACHINE, "SAC Initialize Machine Information:: MachineInformationBuffer already initialized.\n");
706 return;
707 }
708
709 /* Allocate the machine information */
710 MachineInformation = SacAllocatePool(sizeof(*MachineInformation),
711 GLOBAL_BLOCK_TAG);
712 if (!MachineInformation)
713 {
714 goto Fail;
715 }
716
717 /* Zero it out for now */
718 RtlZeroMemory(MachineInformation, sizeof(*MachineInformation));
719
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))
725 {
726 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (2).\n");
727 goto Fail;
728 }
729
730 /* Check if setup is in progress */
731 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\Setup",
732 L"SystemSetupInProgress",
733 &PartialInfo);
734 if (NT_SUCCESS(Status))
735 {
736 /* The key is there, is the value set? */
737 if (*(PULONG)PartialInfo->Data) SetupInProgress = TRUE;
738 SacFreePool(PartialInfo);
739 if (SetupInProgress)
740 {
741 /* Yes, so we'll use a special hostname to identify this */
742 MessageBuffer = GetMessage(SAC_UNINITIALIZED_MSG);
743 Size = wcslen(MessageBuffer);
744 ASSERT(Size > 0);
745 RealSize = Size * sizeof(WCHAR) + sizeof(UNICODE_NULL);
746
747 /* Make room for it and copy it in there */
748 MachineInformation->MachineName = SacAllocatePool(RealSize,
749 GLOBAL_BLOCK_TAG);
750 if (MachineInformation->MachineName)
751 {
752 wcscpy(MachineInformation->MachineName, MessageBuffer);
753 }
754 }
755 }
756
757 /* If we are not in setup mode, or if we failed to check... */
758 if (!SetupInProgress)
759 {
760 /* Query the computer name */
761 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\"
762 L"CurrentControlSet\\Control\\"
763 L"ComputerName\\ComputerName",
764 L"ComputerName",
765 &PartialInfo);
766 if (!NT_SUCCESS(Status))
767 {
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");
770 }
771 else
772 {
773 /* We have the name, copy it from the registry */
774 Status = CopyRegistryValueData((PVOID*)&MachineInformation->
775 MachineName,
776 PartialInfo);
777 SacFreePool(PartialInfo);
778 if (!NT_SUCCESS(Status))
779 {
780 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (20).\n");
781 goto Fail;
782 }
783 }
784 }
785
786 /* Next step, try to get the machine GUID */
787 RtlZeroMemory(&SystemGuid, sizeof(SystemGuid));
788 OutputSize = sizeof(SystemGuid);
789 Status = HeadlessDispatch(HeadlessCmdQueryGUID,
790 NULL,
791 0,
792 &SystemGuid,
793 &OutputSize);
794 if (!NT_SUCCESS(Status))
795 {
796 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Failed to get Machine GUID.\n");
797 }
798 else
799 {
800 /* We have it -- make room for it */
801 GuidString = SacAllocatePool(0x50, GLOBAL_BLOCK_TAG);
802 if (!GuidString)
803 {
804 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (31).\n");
805 goto Fail;
806 }
807
808 /* Build the string with the GUID in it, and save the ppointer to it */
809 swprintf(GuidString,
810 L"%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
811 SystemGuid.Data1,
812 SystemGuid.Data2,
813 SystemGuid.Data3,
814 SystemGuid.Data4[0],
815 SystemGuid.Data4[1],
816 SystemGuid.Data4[2],
817 SystemGuid.Data4[3],
818 SystemGuid.Data4[4],
819 SystemGuid.Data4[5],
820 SystemGuid.Data4[6],
821 SystemGuid.Data4[7]);
822 MachineInformation->MachineGuid = GuidString;
823 }
824
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",
830 &PartialInfo);
831 if (!NT_SUCCESS(Status))
832 {
833 /* It's not critical, but we won't have it */
834 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (30).\n");
835 }
836 else
837 {
838 /* We have it! Copy the value from the registry */
839 Status = CopyRegistryValueData((PVOID*)&MachineInformation->
840 ProcessorArchitecture,
841 PartialInfo);
842 SacFreePool(PartialInfo);
843 if (!NT_SUCCESS(Status))
844 {
845 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (30).\n");
846 goto Fail;
847 }
848 }
849
850 /* Now allocate a buffer for the OS version number */
851 MajorVersion = SacAllocatePool(0x18, GLOBAL_BLOCK_TAG);
852 if (!MajorVersion)
853 {
854 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (50).\n");
855 goto Fail;
856 }
857
858 /* Build the buffer and set a pointer to it */
859 swprintf(MajorVersion,
860 L"%d.%d",
861 VersionInformation.dwMajorVersion,
862 VersionInformation.dwMinorVersion);
863 MachineInformation->MajorVersion = MajorVersion;
864
865 /* Now allocate a buffer for the OS build number */
866 BuildNumber = SacAllocatePool(0xC, GLOBAL_BLOCK_TAG);
867 if (!BuildNumber)
868 {
869 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (60).\n");
870 goto Fail;
871 }
872
873 /* Build the buffer and set a pointer to it */
874 swprintf(BuildNumber, L"%d", VersionInformation.dwBuildNumber);
875 MachineInformation->BuildNumber = BuildNumber;
876
877 /* Now check what kind of SKU this is */
878 if (ExVerifySuite(DataCenter))
879 {
880 SuiteTypeMessage = SAC_DATACENTER_SUITE_MSG;
881 }
882 else if (ExVerifySuite(EmbeddedNT))
883 {
884 SuiteTypeMessage = SAC_EMBEDDED_SUITE_MSG;
885 }
886 else if (ExVerifySuite(Enterprise))
887 {
888 SuiteTypeMessage = SAC_ENTERPRISE_SUITE_MSG;
889 }
890 else
891 {
892 /* Unknown or perhaps a client SKU */
893 SuiteTypeMessage = SAC_NO_SUITE_MSG;
894 }
895
896 /* Get the string that corresponds to the SKU type */
897 MessageBuffer = GetMessage(SuiteTypeMessage);
898 if (!MessageBuffer)
899 {
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");
902 }
903 else
904 {
905 /* Calculate the size we need to hold the string */
906 Size = wcslen(MessageBuffer);
907 ASSERT(Size > 0);
908 RealSize = Size * sizeof(WCHAR) + sizeof(UNICODE_NULL);
909
910 /* Allocate a buffer for it */
911 ProductType = SacAllocatePool(RealSize, GLOBAL_BLOCK_TAG);
912 if (!ProductType)
913 {
914 SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed product type memory allocation.\n");
915 goto Fail;
916 }
917
918 /* Copy the string and set the pointer */
919 RtlCopyMemory(ProductType, MessageBuffer, RealSize);
920 MachineInformation->ProductType = ProductType;
921 }
922
923 /* Check if this is a SP version or RTM version */
924 if (VersionInformation.wServicePackMajor)
925 {
926 /* This is a service pack, allocate a buffer for the version */
927 ServicePack = SacAllocatePool(0x18, GLOBAL_BLOCK_TAG);
928 if (ServicePack)
929 {
930 /* Build the buffer and set a pointer to it */
931 swprintf(ServicePack,
932 L"%d.%d",
933 VersionInformation.wServicePackMajor,
934 VersionInformation.wServicePackMinor);
935 MachineInformation->ServicePack = ServicePack;
936
937 /* We've collected all the machine info and are done! */
938 return;
939 }
940
941 /* This is the failure path */
942 SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed service pack memory allocation.\n");
943 }
944 else
945 {
946 /* Get a generic string that indicates there's no service pack */
947 MessageBuffer = GetMessage(SAC_NO_DATA_MSG);
948 Size = wcslen(MessageBuffer);
949 ASSERT(Size > 0);
950 RealSize = Size * sizeof(WCHAR) + sizeof(UNICODE_NULL);
951
952 /* Allocate memory for the "no service pack" string */
953 ServicePack = SacAllocatePool(RealSize, GLOBAL_BLOCK_TAG);
954 if (ServicePack)
955 {
956 /* Copy the buffer and set a pointer to it */
957 RtlCopyMemory(ServicePack, MessageBuffer, RealSize);
958 MachineInformation->ServicePack = ServicePack;
959
960 /* We've collected all the machine info and are done! */
961 return;
962 }
963
964 SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed service pack memory allocation.\n");
965 }
966
967 Fail:
968 /* In the failure path, always cleanup the machine information buffer */
969 if (MachineInformation)
970 {
971 SacFreePool(MachineInformation);
972 }
973 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC Initialize Machine Information : Exiting with error.\n");
974 }
975
976 NTSTATUS
977 NTAPI
978 GetCommandConsoleLaunchingPermission(OUT PBOOLEAN Permission)
979 {
980 NTSTATUS Status;
981 PKEY_VALUE_PARTIAL_INFORMATION Dummy;
982
983 /* Assume success and read the key */
984 *Permission = TRUE;
985 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacdrv",
986 L"DisableCmdSessions",
987 &Dummy);
988 if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
989 {
990 /* The default is success */
991 Status = STATUS_SUCCESS;
992 }
993 else
994 {
995 /* Only if the key is present and set, do we disable permission */
996 if (NT_SUCCESS(Status)) *Permission = FALSE;
997 }
998
999 /* Return status */
1000 return Status;
1001 }
1002
1003 NTSTATUS
1004 NTAPI
1005 ImposeSacCmdServiceStartTypePolicy(VOID)
1006 {
1007 NTSTATUS Status;
1008 PKEY_VALUE_PARTIAL_INFORMATION Buffer = NULL;
1009 PULONG Data;
1010
1011 /* Read the service start type*/
1012 Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacsvr",
1013 L"Start",
1014 &Buffer);
1015 if (!NT_SUCCESS(Status)) return Status;
1016
1017 /* If there's no start type, fail, as this is unusual */
1018 if (!Buffer) return STATUS_UNSUCCESSFUL;
1019
1020 /* Read the value */
1021 Status = CopyRegistryValueData((PVOID*)&Data, Buffer);
1022 SacFreePool(Buffer);
1023 if (!NT_SUCCESS(Status)) return Status;
1024
1025 /* Check what the current start type is */
1026 switch (*Data)
1027 {
1028 /* It's boot, system, or disabled */
1029 case 1:
1030 case 2:
1031 case 4:
1032 /* Leave it as is */
1033 return Status;
1034
1035 case 3:
1036
1037 /* It's set to automatic, set it to system instead */
1038 *Data = 2;
1039 Status = SetRegistryValue(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacsvr",
1040 L"Start",
1041 REG_DWORD,
1042 Data,
1043 sizeof(ULONG));
1044 if (!NT_SUCCESS(Status))
1045 {
1046 SAC_DBG(SAC_DBG_INIT, "SAC ImposeSacCmdServiceStartTypePolicy: Failed SetRegistryValue: %X\n", Status);
1047 }
1048 break;
1049
1050 default:
1051 ASSERT(FALSE);
1052 }
1053
1054 return Status;
1055 }
1056
1057 VOID
1058 NTAPI
1059 InitializeCmdEventInfo(VOID)
1060 {
1061 /* Check if we were already initialized */
1062 if (HaveUserModeServiceCmdEventInfo)
1063 {
1064 /* Full state expected */
1065 ASSERT(RequestSacCmdEventObjectBody);
1066 ASSERT(RequestSacCmdSuccessEventObjectBody);
1067 ASSERT(RequestSacCmdFailureEventObjectBody);
1068
1069 /* Dereference each wait object in turn */
1070 if (RequestSacCmdEventObjectBody)
1071 {
1072 ObDereferenceObject(RequestSacCmdEventObjectBody);
1073 }
1074
1075 if (RequestSacCmdSuccessEventObjectBody)
1076 {
1077 ObDereferenceObject(RequestSacCmdSuccessEventObjectBody);
1078 }
1079
1080 if (RequestSacCmdFailureEventObjectBody)
1081 {
1082 ObDereferenceObject(RequestSacCmdFailureEventObjectBody);
1083 }
1084 }
1085
1086 /* Claer everything */
1087 RequestSacCmdEventObjectBody = NULL;
1088 RequestSacCmdEventWaitObjectBody = NULL;
1089 RequestSacCmdSuccessEventObjectBody = NULL;
1090 RequestSacCmdSuccessEventWaitObjectBody = NULL;
1091 RequestSacCmdFailureEventObjectBody = NULL;
1092 RequestSacCmdFailureEventWaitObjectBody = NULL;
1093 ServiceProcessFileObject = NULL;
1094
1095 /* Reset state */
1096 HaveUserModeServiceCmdEventInfo = FALSE;
1097 }
1098
1099 NTSTATUS
1100 NTAPI
1101 RegisterBlueScreenMachineInformation(VOID)
1102 {
1103 PWCHAR XmlBuffer;
1104 PHEADLESS_CMD_SET_BLUE_SCREEN_DATA BsBuffer;
1105 SIZE_T Length, HeaderLength, TotalLength;
1106 NTSTATUS Status;
1107 ULONG i;
1108
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);
1113
1114 /* Compute the sizes and allocate a buffer for it */
1115 Length = wcslen(XmlBuffer);
1116 HeaderLength = strlen("MACHINEINFO");
1117 TotalLength = HeaderLength +
1118 Length +
1119 sizeof(*BsBuffer) +
1120 2 * sizeof(ANSI_NULL);
1121 BsBuffer = SacAllocatePool(TotalLength, GLOBAL_BLOCK_TAG);
1122 CHECK_PARAMETER_WITH_STATUS(BsBuffer, STATUS_NO_MEMORY);
1123
1124 /* Copy the XML property name */
1125 strcpy((PCHAR)BsBuffer->Data, "MACHINEINFO");
1126 BsBuffer->ValueIndex = HeaderLength + sizeof(ANSI_NULL);
1127
1128 /* Copy the data and NULL-terminate it */
1129 for (i = 0; i < Length; i++)
1130 {
1131 BsBuffer->Data[BsBuffer->ValueIndex + i] = XmlBuffer[i];
1132 }
1133 BsBuffer->Data[BsBuffer->ValueIndex + i] = ANSI_NULL;
1134
1135 /* Let the OS save the buffer for later */
1136 Status = HeadlessDispatch(HeadlessCmdSetBlueScreenData,
1137 BsBuffer,
1138 TotalLength,
1139 NULL,
1140 NULL);
1141
1142 /* Failure or not, we don't need this anymore */
1143 SacFreePool(BsBuffer);
1144 SacFreePool(XmlBuffer);
1145
1146 /* Return the result */
1147 SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC Initialize Machine Information: Exiting.\n");
1148 return Status;
1149 }
1150
1151 VOID
1152 NTAPI
1153 FreeMachineInformation(VOID)
1154 {
1155 ASSERT(MachineInformation);
1156
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);
1165 }
1166
1167 BOOLEAN
1168 NTAPI
1169 VerifyEventWaitable(IN HANDLE Handle,
1170 OUT PVOID *WaitObject,
1171 OUT PVOID *ActualWaitObject)
1172 {
1173 PVOID Object;
1174 NTSTATUS Status;
1175 POBJECT_TYPE ObjectType;
1176
1177 /* Reference the object */
1178 Status = ObReferenceObjectByHandle(Handle,
1179 EVENT_ALL_ACCESS,
1180 NULL,
1181 KernelMode,
1182 &Object,
1183 NULL);
1184 *WaitObject = Object;
1185 if (!NT_SUCCESS(Status))
1186 {
1187 SAC_DBG(SAC_DBG_INIT, "SAC VerifyEventWaitable: Unable to reference event object (%lx)\n", Status);
1188 return FALSE;
1189 }
1190
1191 /* Check if the object itself is NOT being used */
1192 ObjectType = OBJECT_TO_OBJECT_HEADER(Object)->Type;
1193 if (ObjectType->TypeInfo.UseDefaultObject == FALSE)
1194 {
1195 /* Get the actual object that's being used for the wait */
1196 *ActualWaitObject = (PVOID)((ULONG_PTR)Object +
1197 (ULONG_PTR)ObjectType->DefaultObject);
1198 return TRUE;
1199 }
1200
1201 /* Drop the reference we took */
1202 SAC_DBG(SAC_DBG_INIT, "SAC VerifyEventWaitable: event object not waitable!\n");
1203 ObDereferenceObject(*WaitObject);
1204 return FALSE;
1205 }
1206
1207 NTSTATUS
1208 NTAPI
1209 SerialBufferGetChar(OUT PCHAR Char)
1210 {
1211 /* Check if nothing's been produced yet */
1212 if (SerialPortConsumerIndex == SerialPortProducerIndex)
1213 {
1214 return STATUS_NO_DATA_DETECTED;
1215 }
1216
1217 /* Consume the produced character and clear it*/
1218 *Char = SerialPortBuffer[SerialPortConsumerIndex];
1219 SerialPortBuffer[SerialPortConsumerIndex] = ANSI_NULL;
1220
1221 /* Advance the index and return success */
1222 _InterlockedExchange(&SerialPortConsumerIndex,
1223 (SerialPortConsumerIndex + 1) &
1224 (SAC_SERIAL_PORT_BUFFER_SIZE - 1));
1225 return STATUS_SUCCESS;
1226 }
1227
1228 ULONG
1229 NTAPI
1230 GetMessageLineCount(IN ULONG MessageIndex)
1231 {
1232 ULONG LineCount = 0;
1233 PWCHAR Buffer;
1234
1235 /* Get the message buffer */
1236 Buffer = GetMessage(MessageIndex);
1237 if (Buffer)
1238 {
1239 /* Scan it looking for new lines, and increment the count each time */
1240 while (*Buffer) if (*Buffer++ == L'\n') ++LineCount;
1241 }
1242
1243 /* Return the line count */
1244 return LineCount;
1245 }
1246
1247 ULONG
1248 ConvertAnsiToUnicode(
1249 IN PWCHAR pwch,
1250 IN PCHAR pch,
1251 IN ULONG length
1252 )
1253 {
1254 return STATUS_NOT_IMPLEMENTED;
1255 }
1256
1257 BOOLEAN
1258 IsCmdEventRegistrationProcess(
1259 IN PFILE_OBJECT FileObject
1260 )
1261 {
1262 return FALSE;
1263 }
1264
1265 NTSTATUS
1266 InvokeUserModeService(
1267 VOID
1268 )
1269 {
1270 return STATUS_NOT_IMPLEMENTED;
1271 }
1272
1273 NTSTATUS
1274 TranslateMachineInformationText(
1275 IN PWCHAR Buffer)
1276 {
1277 return STATUS_NOT_IMPLEMENTED;
1278 }
1279
1280 NTSTATUS
1281 CopyAndInsertStringAtInterval(
1282 IN PWCHAR SourceStr,
1283 IN ULONG Interval,
1284 IN PWCHAR InsertStr,
1285 OUT PWCHAR pDestStr
1286 )
1287 {
1288 return STATUS_NOT_IMPLEMENTED;
1289 }
1290
1291 NTSTATUS
1292 RegisterSacCmdEvent(
1293 IN PVOID Object,
1294 IN PKEVENT SetupCmdEvent[]
1295 )
1296 {
1297 return STATUS_NOT_IMPLEMENTED;
1298 }
1299
1300 NTSTATUS
1301 UnregisterSacCmdEvent(
1302 IN PFILE_OBJECT FileObject
1303 )
1304 {
1305 return STATUS_NOT_IMPLEMENTED;
1306 }