xref: /reactos/drivers/sac/driver/util.c (revision ed125de9)
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