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