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
SacTranslateUtf8ToUnicode(IN CHAR Utf8Char,IN PCHAR Utf8Buffer,OUT PWCHAR Utf8Value)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
SacTranslateUnicodeToUtf8(IN PWCHAR SourceBuffer,IN ULONG SourceBufferLength,OUT PCHAR DestinationBuffer,IN ULONG DestinationBufferSize,OUT PULONG UTF8Count,OUT PULONG ProcessedCount)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
GetMessage(IN ULONG MessageIndex)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
UTF8EncodeAndSend(IN PWCHAR String)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
SacFormatMessage(IN PWCHAR FormattedString,IN PWCHAR MessageString,IN ULONG MessageSize)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
PreloadGlobalMessageTable(IN PVOID ImageBase)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
TearDownGlobalMessageTable(VOID)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
GetRegistryValueBuffer(IN PCWSTR KeyName,IN PWCHAR ValueName,IN PKEY_VALUE_PARTIAL_INFORMATION * Buffer)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 | 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
456 Quit:
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
463 NTSTATUS
464 NTAPI
SetRegistryValue(IN PCWSTR KeyName,IN PWCHAR ValueName,IN ULONG Type,IN PVOID Data,IN ULONG DataSize)465 SetRegistryValue(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
512 NTSTATUS
513 NTAPI
CopyRegistryValueData(IN PVOID * Buffer,IN PKEY_VALUE_PARTIAL_INFORMATION PartialInfo)514 CopyRegistryValueData(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
539 NTSTATUS
540 NTAPI
TranslateMachineInformationXML(IN PWCHAR * Buffer,IN PWCHAR ExtraData)541 TranslateMachineInformationXML(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
690 VOID
691 NTAPI
InitializeMachineInformation(VOID)692 InitializeMachineInformation(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
970 Fail:
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
979 NTSTATUS
980 NTAPI
GetCommandConsoleLaunchingPermission(OUT PBOOLEAN Permission)981 GetCommandConsoleLaunchingPermission(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
1006 NTSTATUS
1007 NTAPI
ImposeSacCmdServiceStartTypePolicy(VOID)1008 ImposeSacCmdServiceStartTypePolicy(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
1060 VOID
1061 NTAPI
InitializeCmdEventInfo(VOID)1062 InitializeCmdEventInfo(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
1102 NTSTATUS
1103 NTAPI
RegisterBlueScreenMachineInformation(VOID)1104 RegisterBlueScreenMachineInformation(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
1154 VOID
1155 NTAPI
FreeMachineInformation(VOID)1156 FreeMachineInformation(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
1170 BOOLEAN
1171 NTAPI
VerifyEventWaitable(IN HANDLE Handle,OUT PVOID * WaitObject,OUT PVOID * ActualWaitObject)1172 VerifyEventWaitable(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
1210 NTSTATUS
1211 NTAPI
SerialBufferGetChar(OUT PCHAR Char)1212 SerialBufferGetChar(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
1231 ULONG
1232 NTAPI
GetMessageLineCount(IN ULONG MessageIndex)1233 GetMessageLineCount(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
1250 ULONG
ConvertAnsiToUnicode(IN PWCHAR pwch,IN PCHAR pch,IN ULONG length)1251 ConvertAnsiToUnicode(
1252 IN PWCHAR pwch,
1253 IN PCHAR pch,
1254 IN ULONG length
1255 )
1256 {
1257 return STATUS_NOT_IMPLEMENTED;
1258 }
1259
1260 BOOLEAN
IsCmdEventRegistrationProcess(IN PFILE_OBJECT FileObject)1261 IsCmdEventRegistrationProcess(
1262 IN PFILE_OBJECT FileObject
1263 )
1264 {
1265 return FALSE;
1266 }
1267
1268 NTSTATUS
InvokeUserModeService(VOID)1269 InvokeUserModeService(
1270 VOID
1271 )
1272 {
1273 return STATUS_NOT_IMPLEMENTED;
1274 }
1275
1276 NTSTATUS
TranslateMachineInformationText(IN PWCHAR Buffer)1277 TranslateMachineInformationText(
1278 IN PWCHAR Buffer)
1279 {
1280 return STATUS_NOT_IMPLEMENTED;
1281 }
1282
1283 NTSTATUS
CopyAndInsertStringAtInterval(IN PWCHAR SourceStr,IN ULONG Interval,IN PWCHAR InsertStr,OUT PWCHAR pDestStr)1284 CopyAndInsertStringAtInterval(
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
1294 NTSTATUS
RegisterSacCmdEvent(IN PVOID Object,IN PKEVENT SetupCmdEvent[])1295 RegisterSacCmdEvent(
1296 IN PVOID Object,
1297 IN PKEVENT SetupCmdEvent[]
1298 )
1299 {
1300 return STATUS_NOT_IMPLEMENTED;
1301 }
1302
1303 NTSTATUS
UnregisterSacCmdEvent(IN PFILE_OBJECT FileObject)1304 UnregisterSacCmdEvent(
1305 IN PFILE_OBJECT FileObject
1306 )
1307 {
1308 return STATUS_NOT_IMPLEMENTED;
1309 }
1310