mirror of
https://github.com/reactos/reactos.git
synced 2024-12-29 10:35:28 +00:00
1306 lines
40 KiB
C
1306 lines
40 KiB
C
/*
|
|
* PROJECT: ReactOS Drivers
|
|
* LICENSE: BSD - See COPYING.ARM in the top level directory
|
|
* FILE: drivers/sac/driver/util.c
|
|
* PURPOSE: Driver for the Server Administration Console (SAC) for EMS
|
|
* PROGRAMMERS: ReactOS Portable Systems Group
|
|
*/
|
|
|
|
/* INCLUDES *******************************************************************/
|
|
|
|
#include "sacdrv.h"
|
|
|
|
#include <ndk/rtlfuncs.h>
|
|
|
|
/* GLOBALS ********************************************************************/
|
|
|
|
PCHAR Utf8ConversionBuffer;
|
|
ULONG Utf8ConversionBufferSize = PAGE_SIZE;
|
|
|
|
PSAC_MACHINE_INFO MachineInformation;
|
|
|
|
PVOID RequestSacCmdEventObjectBody;
|
|
PKEVENT RequestSacCmdEventWaitObjectBody;
|
|
PVOID RequestSacCmdSuccessEventObjectBody;
|
|
PKEVENT RequestSacCmdSuccessEventWaitObjectBody;
|
|
PVOID RequestSacCmdFailureEventObjectBody;
|
|
PKEVENT RequestSacCmdFailureEventWaitObjectBody;
|
|
PFILE_OBJECT ServiceProcessFileObject;
|
|
BOOLEAN HaveUserModeServiceCmdEventInfo;
|
|
|
|
PSAC_MESSAGE_ENTRY GlobalMessageTable;
|
|
ULONG GlobalMessageTableCount;
|
|
|
|
LONG SerialPortConsumerIndex, SerialPortProducerIndex;
|
|
PCHAR SerialPortBuffer;
|
|
|
|
/* FUNCTIONS ******************************************************************/
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
SacTranslateUtf8ToUnicode(IN CHAR Utf8Char,
|
|
IN PCHAR Utf8Buffer,
|
|
OUT PWCHAR Utf8Value)
|
|
{
|
|
ULONG i;
|
|
|
|
/* Find out how many valid characters we have in the buffer */
|
|
i = 0;
|
|
while (Utf8Buffer[i++] && (i < 3));
|
|
|
|
/* If we have at least 3, shift everything by a byte */
|
|
if (i >= 3)
|
|
{
|
|
/* The last input character goes at the end */
|
|
Utf8Buffer[0] = Utf8Buffer[1];
|
|
Utf8Buffer[1] = Utf8Buffer[2];
|
|
Utf8Buffer[2] = Utf8Char;
|
|
}
|
|
else
|
|
{
|
|
/* We don't have more than 3 characters, place the input at the index */
|
|
Utf8Buffer[i] = Utf8Char;
|
|
}
|
|
|
|
/* Print to debugger */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SacTranslateUtf8ToUnicode - About to decode the UTF8 buffer.\n");
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, " UTF8[0]: 0x%02lx UTF8[1]: 0x%02lx UTF8[2]: 0x%02lx\n",
|
|
Utf8Buffer[0],
|
|
Utf8Buffer[1],
|
|
Utf8Buffer[2]);
|
|
|
|
/* Is this a simple ANSI character? */
|
|
if (!(Utf8Char & 0x80))
|
|
{
|
|
/* Return it as Unicode, nothing left to do */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SACDRV: SacTranslateUTf8ToUnicode - Case1\n");
|
|
*Utf8Value = (WCHAR)Utf8Char;
|
|
Utf8Buffer[0] = Utf8Buffer[1];
|
|
Utf8Buffer[1] = Utf8Buffer[2];
|
|
Utf8Buffer[2] = UNICODE_NULL;
|
|
return TRUE;
|
|
}
|
|
|
|
/* Anything else is not yet supported */
|
|
ASSERT(FALSE);
|
|
return FALSE;
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
SacTranslateUnicodeToUtf8(IN PWCHAR SourceBuffer,
|
|
IN ULONG SourceBufferLength,
|
|
OUT PCHAR DestinationBuffer,
|
|
IN ULONG DestinationBufferSize,
|
|
OUT PULONG UTF8Count,
|
|
OUT PULONG ProcessedCount)
|
|
{
|
|
*UTF8Count = 0;
|
|
*ProcessedCount = 0;
|
|
|
|
while ((*SourceBuffer) &&
|
|
(*UTF8Count < DestinationBufferSize) &&
|
|
(*ProcessedCount < SourceBufferLength))
|
|
{
|
|
if (*SourceBuffer & 0xFF80)
|
|
{
|
|
if (*SourceBuffer & 0xF800)
|
|
{
|
|
if ((*UTF8Count + 3) >= DestinationBufferSize) break;
|
|
DestinationBuffer[*UTF8Count] = ((*SourceBuffer >> 12) & 0xF) | 0xE0;
|
|
++*UTF8Count;
|
|
DestinationBuffer[*UTF8Count] = ((*SourceBuffer >> 6) & 0x3F) | 0x80;
|
|
}
|
|
else
|
|
{
|
|
if ((*UTF8Count + 2) >= DestinationBufferSize) break;
|
|
DestinationBuffer[*UTF8Count] = ((*SourceBuffer >> 6) & 31) | 0xC0;
|
|
}
|
|
++*UTF8Count;
|
|
DestinationBuffer[*UTF8Count] = (*SourceBuffer & 0x3F) | 0x80;
|
|
}
|
|
else
|
|
{
|
|
DestinationBuffer[*UTF8Count] = (*SourceBuffer & 0x7F);
|
|
}
|
|
|
|
++*UTF8Count;
|
|
++*ProcessedCount;
|
|
++SourceBuffer;
|
|
}
|
|
|
|
ASSERT(*ProcessedCount <= SourceBufferLength);
|
|
ASSERT(*UTF8Count <= DestinationBufferSize);
|
|
return TRUE;
|
|
}
|
|
|
|
PWCHAR
|
|
NTAPI
|
|
GetMessage(IN ULONG MessageIndex)
|
|
{
|
|
PSAC_MESSAGE_ENTRY MessageEntry;
|
|
ULONG i;
|
|
PWCHAR MessageData = NULL;
|
|
|
|
/* Loop all cached messages */
|
|
for (i = 0; i < GlobalMessageTableCount; i++)
|
|
{
|
|
/* Check if this one matches the index */
|
|
MessageEntry = &GlobalMessageTable[i];
|
|
if (MessageEntry->Index == MessageIndex)
|
|
{
|
|
/* It does, return the buffer */
|
|
MessageData = MessageEntry->Buffer;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* We should always find it */
|
|
if (!MessageData) ASSERT(FALSE);
|
|
return MessageData;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
UTF8EncodeAndSend(IN PWCHAR String)
|
|
{
|
|
ULONG ProcessedCount, Utf8Count, i;
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
/* Call the translator routine */
|
|
if (SacTranslateUnicodeToUtf8(String,
|
|
wcslen(String),
|
|
Utf8ConversionBuffer,
|
|
Utf8ConversionBufferSize,
|
|
&Utf8Count,
|
|
&ProcessedCount))
|
|
{
|
|
/* Loop every character */
|
|
for (i = 0; i < Utf8Count; i++)
|
|
{
|
|
/* Send it to the terminal */
|
|
Status = HeadlessDispatch(HeadlessCmdPutData,
|
|
&Utf8ConversionBuffer[i],
|
|
sizeof(Utf8ConversionBuffer[i]),
|
|
NULL,
|
|
NULL);
|
|
if (!NT_SUCCESS(Status)) break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Conversion failed */
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
}
|
|
|
|
/* All done */
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
SacFormatMessage(IN PWCHAR FormattedString,
|
|
IN PWCHAR MessageString,
|
|
IN ULONG MessageSize)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SacFormatMessage: Entering.\n");
|
|
|
|
/* Check if any of the parameters are NULL or zero */
|
|
if (!(MessageString) || !(FormattedString) || !(MessageSize))
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SacFormatMessage: Exiting with invalid parameters.\n");
|
|
return;
|
|
}
|
|
|
|
/* Keep going as long as there's still characters */
|
|
while ((MessageString[0]) && (MessageSize))
|
|
{
|
|
/* Is it a non-formatting character? */
|
|
if (MessageString[0] != L'%')
|
|
{
|
|
/* Just write it back into the buffer and keep going */
|
|
*FormattedString++ = MessageString[0];
|
|
MessageString++;
|
|
}
|
|
else
|
|
{
|
|
/* Go over the format characters we recognize */
|
|
switch (MessageString[1])
|
|
{
|
|
case L'0':
|
|
*FormattedString = UNICODE_NULL;
|
|
return;
|
|
|
|
case L'%':
|
|
*FormattedString++ = L'%';
|
|
break;
|
|
|
|
case L'\\':
|
|
*FormattedString++ = L'\r';
|
|
*FormattedString++ = L'\n';
|
|
break;
|
|
|
|
case L'r':
|
|
*FormattedString++ = L'\r';
|
|
break;
|
|
|
|
case L'b':
|
|
*FormattedString++ = L' ';
|
|
break;
|
|
|
|
case L'.':
|
|
*FormattedString++ = L'.';
|
|
break;
|
|
|
|
case L'!':
|
|
*FormattedString++ = L'!';
|
|
break;
|
|
|
|
default:
|
|
/* Only move forward one character */
|
|
MessageString--;
|
|
break;
|
|
}
|
|
|
|
/* Move forward two characters */
|
|
MessageString += 2;
|
|
}
|
|
|
|
/* Move to the next character*/
|
|
MessageSize--;
|
|
}
|
|
|
|
/* All done */
|
|
*FormattedString = UNICODE_NULL;
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SacFormatMessage: Exiting.\n");
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
PreloadGlobalMessageTable(IN PVOID ImageBase)
|
|
{
|
|
NTSTATUS Status, Status2;
|
|
ULONG MessageId, TotalLength, TextSize, i;
|
|
PWCHAR StringBuffer;
|
|
PMESSAGE_RESOURCE_ENTRY MessageEntry;
|
|
PAGED_CODE();
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC PreloadGlobalMessageTable: Entering.\n");
|
|
|
|
/* Nothing to do if we already have a table */
|
|
Status = STATUS_SUCCESS;
|
|
if (GlobalMessageTable) goto Exit;
|
|
|
|
/* Loop through up to 200 messages */
|
|
TotalLength = 0;
|
|
for (MessageId = 1; MessageId != SAC_MAX_MESSAGES; MessageId++)
|
|
{
|
|
/* Find this message ID in the string table*/
|
|
Status2 = RtlFindMessage(ImageBase,
|
|
11,
|
|
LANG_NEUTRAL,
|
|
MessageId,
|
|
&MessageEntry);
|
|
if (NT_SUCCESS(Status2))
|
|
{
|
|
/* Make sure it's Unicode */
|
|
ASSERT(MessageEntry->Flags & MESSAGE_RESOURCE_UNICODE);
|
|
|
|
/* Remove the space taken up by the OS header, and add our own */
|
|
TotalLength += MessageEntry->Length -
|
|
FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY, Text) +
|
|
sizeof(SAC_MESSAGE_ENTRY);
|
|
|
|
/* One more in the table */
|
|
GlobalMessageTableCount++;
|
|
}
|
|
}
|
|
|
|
/* We should've found at least one message... */
|
|
if (!TotalLength)
|
|
{
|
|
/* Bail out otherwise */
|
|
SAC_DBG(SAC_DBG_INIT, "SAC PreloadGlobalMessageTable: No Messages.\n");
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
goto Exit;
|
|
}
|
|
|
|
/* Allocate space for the buffers and headers */
|
|
GlobalMessageTable = SacAllocatePool(TotalLength, GLOBAL_BLOCK_TAG);
|
|
if (!GlobalMessageTable)
|
|
{
|
|
/* Bail out if we couldn't allocate it */
|
|
Status = STATUS_NO_MEMORY;
|
|
goto Exit;
|
|
}
|
|
|
|
/* All the buffers are going to be at the end of the table */
|
|
StringBuffer = (PWCHAR)(&GlobalMessageTable[GlobalMessageTableCount]);
|
|
|
|
/* Now loop over our entries again */
|
|
for (i = 0, MessageId = 1; MessageId != SAC_MAX_MESSAGES; MessageId++)
|
|
{
|
|
/* Make sure the message is still there...! */
|
|
Status2 = RtlFindMessage(ImageBase,
|
|
11,
|
|
LANG_NEUTRAL,
|
|
MessageId,
|
|
&MessageEntry);
|
|
if (NT_SUCCESS(Status2))
|
|
{
|
|
/* Write the entry in the message table*/
|
|
GlobalMessageTable[i].Index = MessageId;
|
|
GlobalMessageTable[i].Buffer = StringBuffer;
|
|
|
|
/* The structure includes the size of the header, elide it */
|
|
TextSize = MessageEntry->Length -
|
|
FIELD_OFFSET(MESSAGE_RESOURCE_ENTRY, Text);
|
|
|
|
/* Format the message into the entry. It should be same or smaller */
|
|
SacFormatMessage(StringBuffer, (PWCHAR)MessageEntry->Text, TextSize);
|
|
ASSERT((ULONG)(wcslen(StringBuffer)*sizeof(WCHAR)) <= TextSize);
|
|
|
|
/* Move to the next buffer space */
|
|
StringBuffer += (TextSize / sizeof(WCHAR));
|
|
|
|
/* Move to the next entry, make sure the status is full success */
|
|
i++;
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
}
|
|
|
|
Exit:
|
|
/* All done, return the status code */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC TearDownGlobalMessageTable: Exiting with status 0x%0x\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
TearDownGlobalMessageTable(VOID)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC TearDownGlobalMessageTable: Entering.\n");
|
|
|
|
/* Free the table if one existed */
|
|
if (GlobalMessageTable) SacFreePool(GlobalMessageTable);
|
|
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC TearDownGlobalMessageTable: Exiting\n");
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
GetRegistryValueBuffer(IN PCWSTR KeyName,
|
|
IN PWCHAR ValueName,
|
|
IN PKEY_VALUE_PARTIAL_INFORMATION* Buffer)
|
|
{
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING DestinationString;
|
|
HANDLE Handle;
|
|
ULONG ResultLength = 0;
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: Entering.\n");
|
|
CHECK_PARAMETER1(KeyName);
|
|
CHECK_PARAMETER2(ValueName);
|
|
|
|
/* Open the specified key */
|
|
RtlInitUnicodeString(&DestinationString, KeyName);
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&DestinationString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
Status = ZwOpenKey(&Handle,
|
|
KEY_WRITE | SYNCHRONIZE | KEY_READ,
|
|
&ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Bail out on failure */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: failed ZwOpenKey: %X.\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Query the size of the key */
|
|
RtlInitUnicodeString(&DestinationString, ValueName);
|
|
Status = ZwQueryValueKey(Handle,
|
|
&DestinationString,
|
|
KeyValuePartialInformation,
|
|
NULL,
|
|
0,
|
|
&ResultLength);
|
|
if (!ResultLength) return Status;
|
|
|
|
/* Allocate the buffer for the partial info structure and our integer data */
|
|
ResultLength += sizeof(ULONG);
|
|
*Buffer = SacAllocatePool(ResultLength, GLOBAL_BLOCK_TAG);
|
|
if (!*Buffer)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: failed allocation\n");
|
|
return Status;
|
|
}
|
|
|
|
/* Now read the data */
|
|
Status = ZwQueryValueKey(Handle,
|
|
&DestinationString,
|
|
KeyValuePartialInformation,
|
|
*Buffer,
|
|
ResultLength,
|
|
&ResultLength);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Free the buffer if we couldn't read the data */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC GetRegistryValueBuffer: failed ZwQueryValueKey: %X.\n", Status);
|
|
SacFreePool(*Buffer);
|
|
}
|
|
|
|
/* Return the result */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: Exiting.\n");
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
SetRegistryValue(IN PCWSTR KeyName,
|
|
IN PWCHAR ValueName,
|
|
IN ULONG Type,
|
|
IN PVOID Data,
|
|
IN ULONG DataSize)
|
|
{
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING DestinationString;
|
|
HANDLE Handle;
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: Entering.\n");
|
|
CHECK_PARAMETER1(KeyName);
|
|
CHECK_PARAMETER2(ValueName);
|
|
CHECK_PARAMETER4(Data);
|
|
|
|
/* Open the specified key */
|
|
RtlInitUnicodeString(&DestinationString, KeyName);
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&DestinationString,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
Status = ZwOpenKey(&Handle,
|
|
KEY_WRITE | SYNCHRONIZE | KEY_READ,
|
|
&ObjectAttributes);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Bail out on failure */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: failed ZwOpenKey: %X.\n", Status);
|
|
return Status;
|
|
}
|
|
|
|
/* Set the specified value */
|
|
RtlInitUnicodeString(&DestinationString, ValueName);
|
|
Status = ZwSetValueKey(Handle, &DestinationString, 0, Type, Data, DataSize);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* Print error on failure */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: failed ZwSetValueKey: %X.\n", Status);
|
|
}
|
|
|
|
/* Close the handle and exit */
|
|
NtClose(Handle);
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC SetRegistryValue: Exiting.\n");
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
CopyRegistryValueData(IN PVOID* Buffer,
|
|
IN PKEY_VALUE_PARTIAL_INFORMATION PartialInfo)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
CHECK_PARAMETER1(Buffer);
|
|
CHECK_PARAMETER2(PartialInfo);
|
|
|
|
/* Allocate space for registry data */
|
|
*Buffer = SacAllocatePool(PartialInfo->DataLength, GLOBAL_BLOCK_TAG);
|
|
if (*Buffer)
|
|
{
|
|
/* Copy the data into the buffer */
|
|
RtlCopyMemory(*Buffer, PartialInfo->Data, PartialInfo->DataLength);
|
|
}
|
|
else
|
|
{
|
|
/* Set the correct error code */
|
|
SAC_DBG(SAC_DBG_UTIL, "SAC CopyRegistryValueBuffer: Failed ALLOCATE.\n");
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
|
|
/* Return the result */
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
TranslateMachineInformationXML(IN PWCHAR *Buffer,
|
|
IN PWCHAR ExtraData)
|
|
{
|
|
NTSTATUS Status;
|
|
SIZE_T Size;
|
|
PWCHAR p;
|
|
CHECK_PARAMETER1(Buffer);
|
|
|
|
/* Start by believing the world is beautiful */
|
|
Status = STATUS_SUCCESS;
|
|
|
|
/* First, the header */
|
|
Size = wcslen(L"<machine-info>\r\n");
|
|
|
|
/* Do we have a machine name? */
|
|
if (MachineInformation->MachineName)
|
|
{
|
|
/* Go and add it in */
|
|
Size += wcslen(MachineInformation->MachineName);
|
|
Size += wcslen(L"<name>%s</name>\r\n");
|
|
}
|
|
|
|
/* Do we have a GUID? */
|
|
if (MachineInformation->MachineGuid)
|
|
{
|
|
/* Go and add it in */
|
|
Size += wcslen(MachineInformation->MachineGuid);
|
|
Size += wcslen(L"<guid>%s</guid>\r\n");
|
|
}
|
|
|
|
/* Do we know the processor? */
|
|
if (MachineInformation->ProcessorArchitecture)
|
|
{
|
|
/* Go and add it in */
|
|
Size += wcslen(MachineInformation->ProcessorArchitecture);
|
|
Size += wcslen(L"<processor-architecture>%s</processor-architecture>\r\n");
|
|
}
|
|
|
|
/* Do we have the version? */
|
|
if (MachineInformation->MajorVersion)
|
|
{
|
|
/* Go and add it in */
|
|
Size += wcslen(MachineInformation->MajorVersion);
|
|
Size += wcslen(L"<os-version>%s</os-version>\r\n");
|
|
}
|
|
|
|
/* Do we have the build? */
|
|
if (MachineInformation->BuildNumber)
|
|
{
|
|
/* Go and add it in */
|
|
Size += wcslen(MachineInformation->BuildNumber);
|
|
Size += wcslen(L"<os-build-number>%s</os-build-number>\r\n");
|
|
}
|
|
|
|
/* Do we have the product type? */
|
|
if (MachineInformation->ProductType)
|
|
{
|
|
/* Go and add it in */
|
|
Size += wcslen(MachineInformation->ProductType);
|
|
Size += wcslen(L"<os-product>%s</os-product>\r\n");
|
|
}
|
|
|
|
/* Do we have a service pack? */
|
|
if (MachineInformation->ServicePack)
|
|
{
|
|
/* Go and add it in */
|
|
Size += wcslen(MachineInformation->ServicePack);
|
|
Size += wcslen(L"<os-service-pack>%s</os-service-pack>\r\n");
|
|
}
|
|
|
|
/* Anything else we need to know? Add it in too */
|
|
if (ExtraData) Size += wcslen(ExtraData);
|
|
|
|
/* Finally, add the footer */
|
|
Size += wcslen(L"</machine-info>\r\n");
|
|
|
|
/* Convert to bytes and add a NULL */
|
|
Size += sizeof(ANSI_NULL);
|
|
Size *= sizeof(WCHAR);
|
|
|
|
/* Allocate space for the buffer */
|
|
p = SacAllocatePool(Size, GLOBAL_BLOCK_TAG);
|
|
*Buffer = p;
|
|
if (!p) return STATUS_NO_MEMORY;
|
|
|
|
wcscpy(p, L"<machine-info>\r\n");
|
|
p += wcslen(L"<machine-info>\r\n");
|
|
|
|
if (MachineInformation->MachineName)
|
|
{
|
|
p += swprintf(p,
|
|
L"<name>%s</name>\r\n",
|
|
MachineInformation->MachineName);
|
|
}
|
|
|
|
if (MachineInformation->MachineGuid)
|
|
{
|
|
p += swprintf(p,
|
|
L"<guid>%s</guid>\r\n",
|
|
MachineInformation->MachineGuid);
|
|
}
|
|
|
|
if (MachineInformation->ProcessorArchitecture)
|
|
{
|
|
p += swprintf(p,
|
|
L"<processor-architecture>%s</processor-architecture>\r\n",
|
|
MachineInformation->ProcessorArchitecture);
|
|
}
|
|
|
|
if (MachineInformation->MajorVersion)
|
|
{
|
|
p += swprintf(p,
|
|
L"<os-version>%s</os-version>\r\n",
|
|
MachineInformation->MajorVersion);
|
|
}
|
|
|
|
if (MachineInformation->BuildNumber)
|
|
{
|
|
p += swprintf(p,
|
|
L"<os-build-number>%s</os-build-number>\r\n",
|
|
MachineInformation->BuildNumber);
|
|
}
|
|
|
|
if (MachineInformation->ProductType)
|
|
{
|
|
p += swprintf(p,
|
|
L"<os-product>%s</os-product>\r\n",
|
|
MachineInformation->ProductType);
|
|
}
|
|
|
|
if (MachineInformation->ServicePack)
|
|
{
|
|
p += swprintf(p,
|
|
L"<os-service-pack>%s</os-service-pack>\r\n",
|
|
MachineInformation->ServicePack);
|
|
}
|
|
|
|
if (ExtraData)
|
|
{
|
|
wcscpy(p, ExtraData);
|
|
p += wcslen(ExtraData);
|
|
}
|
|
|
|
wcscpy(p, L"</machine-info>\r\n");
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "MachineInformation: %S\n", *Buffer);
|
|
ASSERT((((ULONG)wcslen(*Buffer) + 1) * sizeof(WCHAR)) <= Size);
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
InitializeMachineInformation(VOID)
|
|
{
|
|
NTSTATUS Status;
|
|
PWCHAR GuidString, MajorVersion, ServicePack, BuildNumber, MessageBuffer;
|
|
PWCHAR ProductType;
|
|
ULONG SuiteTypeMessage;
|
|
BOOLEAN SetupInProgress = FALSE;
|
|
GUID SystemGuid;
|
|
SIZE_T RealSize, Size, OutputSize;
|
|
PKEY_VALUE_PARTIAL_INFORMATION PartialInfo;
|
|
RTL_OSVERSIONINFOEXW VersionInformation;
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC Initialize Machine Information : Entering.\n");
|
|
|
|
/* Don't do anything if we already queried this */
|
|
if (MachineInformation)
|
|
{
|
|
SAC_DBG(SAC_DBG_MACHINE, "SAC Initialize Machine Information:: MachineInformationBuffer already initialized.\n");
|
|
return;
|
|
}
|
|
|
|
/* Allocate the machine information */
|
|
MachineInformation = SacAllocatePool(sizeof(*MachineInformation),
|
|
GLOBAL_BLOCK_TAG);
|
|
if (!MachineInformation)
|
|
{
|
|
goto Fail;
|
|
}
|
|
|
|
/* Zero it out for now */
|
|
RtlZeroMemory(MachineInformation, sizeof(*MachineInformation));
|
|
|
|
/* Query OS version */
|
|
RtlZeroMemory(&VersionInformation, sizeof(VersionInformation));
|
|
VersionInformation.dwOSVersionInfoSize = sizeof(VersionInformation);
|
|
Status = RtlGetVersion((PRTL_OSVERSIONINFOW)&VersionInformation);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (2).\n");
|
|
goto Fail;
|
|
}
|
|
|
|
/* Check if setup is in progress */
|
|
Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\Setup",
|
|
L"SystemSetupInProgress",
|
|
&PartialInfo);
|
|
if (NT_SUCCESS(Status))
|
|
{
|
|
/* The key is there, is the value set? */
|
|
if (*(PULONG)PartialInfo->Data) SetupInProgress = TRUE;
|
|
SacFreePool(PartialInfo);
|
|
if (SetupInProgress)
|
|
{
|
|
/* Yes, so we'll use a special hostname to identify this */
|
|
MessageBuffer = GetMessage(SAC_UNINITIALIZED_MSG);
|
|
Size = wcslen(MessageBuffer);
|
|
ASSERT(Size > 0);
|
|
RealSize = Size * sizeof(WCHAR) + sizeof(UNICODE_NULL);
|
|
|
|
/* Make room for it and copy it in there */
|
|
MachineInformation->MachineName = SacAllocatePool(RealSize,
|
|
GLOBAL_BLOCK_TAG);
|
|
if (MachineInformation->MachineName)
|
|
{
|
|
wcscpy(MachineInformation->MachineName, MessageBuffer);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* If we are not in setup mode, or if we failed to check... */
|
|
if (!SetupInProgress)
|
|
{
|
|
/* Query the computer name */
|
|
Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\"
|
|
L"CurrentControlSet\\Control\\"
|
|
L"ComputerName\\ComputerName",
|
|
L"ComputerName",
|
|
&PartialInfo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* It's not critical, but we won't have it */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Failed to get machine name.\n");
|
|
}
|
|
else
|
|
{
|
|
/* We have the name, copy it from the registry */
|
|
Status = CopyRegistryValueData((PVOID*)&MachineInformation->
|
|
MachineName,
|
|
PartialInfo);
|
|
SacFreePool(PartialInfo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (20).\n");
|
|
goto Fail;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Next step, try to get the machine GUID */
|
|
RtlZeroMemory(&SystemGuid, sizeof(SystemGuid));
|
|
OutputSize = sizeof(SystemGuid);
|
|
Status = HeadlessDispatch(HeadlessCmdQueryGUID,
|
|
NULL,
|
|
0,
|
|
&SystemGuid,
|
|
&OutputSize);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Failed to get Machine GUID.\n");
|
|
}
|
|
else
|
|
{
|
|
/* We have it -- make room for it */
|
|
GuidString = SacAllocatePool(0x50, GLOBAL_BLOCK_TAG);
|
|
if (!GuidString)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (31).\n");
|
|
goto Fail;
|
|
}
|
|
|
|
/* Build the string with the GUID in it, and save the ppointer to it */
|
|
swprintf(GuidString,
|
|
L"%08lx-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
|
SystemGuid.Data1,
|
|
SystemGuid.Data2,
|
|
SystemGuid.Data3,
|
|
SystemGuid.Data4[0],
|
|
SystemGuid.Data4[1],
|
|
SystemGuid.Data4[2],
|
|
SystemGuid.Data4[3],
|
|
SystemGuid.Data4[4],
|
|
SystemGuid.Data4[5],
|
|
SystemGuid.Data4[6],
|
|
SystemGuid.Data4[7]);
|
|
MachineInformation->MachineGuid = GuidString;
|
|
}
|
|
|
|
/* Next, query the processor architecture */
|
|
Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\"
|
|
L"CurrentControlSet\\Control\\"
|
|
L"Session Manager\\Environment",
|
|
L"PROCESSOR_ARCHITECTURE",
|
|
&PartialInfo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
/* It's not critical, but we won't have it */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (30).\n");
|
|
}
|
|
else
|
|
{
|
|
/* We have it! Copy the value from the registry */
|
|
Status = CopyRegistryValueData((PVOID*)&MachineInformation->
|
|
ProcessorArchitecture,
|
|
PartialInfo);
|
|
SacFreePool(PartialInfo);
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (30).\n");
|
|
goto Fail;
|
|
}
|
|
}
|
|
|
|
/* Now allocate a buffer for the OS version number */
|
|
MajorVersion = SacAllocatePool(0x18, GLOBAL_BLOCK_TAG);
|
|
if (!MajorVersion)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (50).\n");
|
|
goto Fail;
|
|
}
|
|
|
|
/* Build the buffer and set a pointer to it */
|
|
swprintf(MajorVersion,
|
|
L"%d.%d",
|
|
VersionInformation.dwMajorVersion,
|
|
VersionInformation.dwMinorVersion);
|
|
MachineInformation->MajorVersion = MajorVersion;
|
|
|
|
/* Now allocate a buffer for the OS build number */
|
|
BuildNumber = SacAllocatePool(0xC, GLOBAL_BLOCK_TAG);
|
|
if (!BuildNumber)
|
|
{
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC InitializeMachineInformation: Exiting (60).\n");
|
|
goto Fail;
|
|
}
|
|
|
|
/* Build the buffer and set a pointer to it */
|
|
swprintf(BuildNumber, L"%d", VersionInformation.dwBuildNumber);
|
|
MachineInformation->BuildNumber = BuildNumber;
|
|
|
|
/* Now check what kind of SKU this is */
|
|
if (ExVerifySuite(DataCenter))
|
|
{
|
|
SuiteTypeMessage = SAC_DATACENTER_SUITE_MSG;
|
|
}
|
|
else if (ExVerifySuite(EmbeddedNT))
|
|
{
|
|
SuiteTypeMessage = SAC_EMBEDDED_SUITE_MSG;
|
|
}
|
|
else if (ExVerifySuite(Enterprise))
|
|
{
|
|
SuiteTypeMessage = SAC_ENTERPRISE_SUITE_MSG;
|
|
}
|
|
else
|
|
{
|
|
/* Unknown or perhaps a client SKU */
|
|
SuiteTypeMessage = SAC_NO_SUITE_MSG;
|
|
}
|
|
|
|
/* Get the string that corresponds to the SKU type */
|
|
MessageBuffer = GetMessage(SuiteTypeMessage);
|
|
if (!MessageBuffer)
|
|
{
|
|
/* We won't have it, but this isn't critical */
|
|
SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed to get product type.\n");
|
|
}
|
|
else
|
|
{
|
|
/* Calculate the size we need to hold the string */
|
|
Size = wcslen(MessageBuffer);
|
|
ASSERT(Size > 0);
|
|
RealSize = Size * sizeof(WCHAR) + sizeof(UNICODE_NULL);
|
|
|
|
/* Allocate a buffer for it */
|
|
ProductType = SacAllocatePool(RealSize, GLOBAL_BLOCK_TAG);
|
|
if (!ProductType)
|
|
{
|
|
SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed product type memory allocation.\n");
|
|
goto Fail;
|
|
}
|
|
|
|
/* Copy the string and set the pointer */
|
|
RtlCopyMemory(ProductType, MessageBuffer, RealSize);
|
|
MachineInformation->ProductType = ProductType;
|
|
}
|
|
|
|
/* Check if this is a SP version or RTM version */
|
|
if (VersionInformation.wServicePackMajor)
|
|
{
|
|
/* This is a service pack, allocate a buffer for the version */
|
|
ServicePack = SacAllocatePool(0x18, GLOBAL_BLOCK_TAG);
|
|
if (ServicePack)
|
|
{
|
|
/* Build the buffer and set a pointer to it */
|
|
swprintf(ServicePack,
|
|
L"%d.%d",
|
|
VersionInformation.wServicePackMajor,
|
|
VersionInformation.wServicePackMinor);
|
|
MachineInformation->ServicePack = ServicePack;
|
|
|
|
/* We've collected all the machine info and are done! */
|
|
return;
|
|
}
|
|
|
|
/* This is the failure path */
|
|
SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed service pack memory allocation.\n");
|
|
}
|
|
else
|
|
{
|
|
/* Get a generic string that indicates there's no service pack */
|
|
MessageBuffer = GetMessage(SAC_NO_DATA_MSG);
|
|
Size = wcslen(MessageBuffer);
|
|
ASSERT(Size > 0);
|
|
RealSize = Size * sizeof(WCHAR) + sizeof(UNICODE_NULL);
|
|
|
|
/* Allocate memory for the "no service pack" string */
|
|
ServicePack = SacAllocatePool(RealSize, GLOBAL_BLOCK_TAG);
|
|
if (ServicePack)
|
|
{
|
|
/* Copy the buffer and set a pointer to it */
|
|
RtlCopyMemory(ServicePack, MessageBuffer, RealSize);
|
|
MachineInformation->ServicePack = ServicePack;
|
|
|
|
/* We've collected all the machine info and are done! */
|
|
return;
|
|
}
|
|
|
|
SAC_DBG(SAC_DBG_INIT, "SAC InitializeMachineInformation: Failed service pack memory allocation.\n");
|
|
}
|
|
|
|
Fail:
|
|
/* In the failure path, always cleanup the machine information buffer */
|
|
if (MachineInformation)
|
|
{
|
|
SacFreePool(MachineInformation);
|
|
}
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC Initialize Machine Information : Exiting with error.\n");
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
GetCommandConsoleLaunchingPermission(OUT PBOOLEAN Permission)
|
|
{
|
|
NTSTATUS Status;
|
|
PKEY_VALUE_PARTIAL_INFORMATION Dummy;
|
|
|
|
/* Assume success and read the key */
|
|
*Permission = TRUE;
|
|
Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacdrv",
|
|
L"DisableCmdSessions",
|
|
&Dummy);
|
|
if (Status == STATUS_OBJECT_NAME_NOT_FOUND)
|
|
{
|
|
/* The default is success */
|
|
Status = STATUS_SUCCESS;
|
|
}
|
|
else
|
|
{
|
|
/* Only if the key is present and set, do we disable permission */
|
|
if (NT_SUCCESS(Status)) *Permission = FALSE;
|
|
}
|
|
|
|
/* Return status */
|
|
return Status;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
ImposeSacCmdServiceStartTypePolicy(VOID)
|
|
{
|
|
NTSTATUS Status;
|
|
PKEY_VALUE_PARTIAL_INFORMATION Buffer = NULL;
|
|
PULONG Data;
|
|
|
|
/* Read the service start type*/
|
|
Status = GetRegistryValueBuffer(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacsvr",
|
|
L"Start",
|
|
&Buffer);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
/* If there's no start type, fail, as this is unusual */
|
|
if (!Buffer) return STATUS_UNSUCCESSFUL;
|
|
|
|
/* Read the value */
|
|
Status = CopyRegistryValueData((PVOID*)&Data, Buffer);
|
|
SacFreePool(Buffer);
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
/* Check what the current start type is */
|
|
switch (*Data)
|
|
{
|
|
/* It's boot, system, or disabled */
|
|
case 1:
|
|
case 2:
|
|
case 4:
|
|
/* Leave it as is */
|
|
return Status;
|
|
|
|
case 3:
|
|
|
|
/* It's set to automatic, set it to system instead */
|
|
*Data = 2;
|
|
Status = SetRegistryValue(L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\sacsvr",
|
|
L"Start",
|
|
REG_DWORD,
|
|
Data,
|
|
sizeof(ULONG));
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SAC_DBG(SAC_DBG_INIT, "SAC ImposeSacCmdServiceStartTypePolicy: Failed SetRegistryValue: %X\n", Status);
|
|
}
|
|
break;
|
|
|
|
default:
|
|
ASSERT(FALSE);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
InitializeCmdEventInfo(VOID)
|
|
{
|
|
/* Check if we were already initialized */
|
|
if (HaveUserModeServiceCmdEventInfo)
|
|
{
|
|
/* Full state expected */
|
|
ASSERT(RequestSacCmdEventObjectBody);
|
|
ASSERT(RequestSacCmdSuccessEventObjectBody);
|
|
ASSERT(RequestSacCmdFailureEventObjectBody);
|
|
|
|
/* Dereference each wait object in turn */
|
|
if (RequestSacCmdEventObjectBody)
|
|
{
|
|
ObDereferenceObject(RequestSacCmdEventObjectBody);
|
|
}
|
|
|
|
if (RequestSacCmdSuccessEventObjectBody)
|
|
{
|
|
ObDereferenceObject(RequestSacCmdSuccessEventObjectBody);
|
|
}
|
|
|
|
if (RequestSacCmdFailureEventObjectBody)
|
|
{
|
|
ObDereferenceObject(RequestSacCmdFailureEventObjectBody);
|
|
}
|
|
}
|
|
|
|
/* Claer everything */
|
|
RequestSacCmdEventObjectBody = NULL;
|
|
RequestSacCmdEventWaitObjectBody = NULL;
|
|
RequestSacCmdSuccessEventObjectBody = NULL;
|
|
RequestSacCmdSuccessEventWaitObjectBody = NULL;
|
|
RequestSacCmdFailureEventObjectBody = NULL;
|
|
RequestSacCmdFailureEventWaitObjectBody = NULL;
|
|
ServiceProcessFileObject = NULL;
|
|
|
|
/* Reset state */
|
|
HaveUserModeServiceCmdEventInfo = FALSE;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
RegisterBlueScreenMachineInformation(VOID)
|
|
{
|
|
PWCHAR XmlBuffer;
|
|
PHEADLESS_CMD_SET_BLUE_SCREEN_DATA BsBuffer;
|
|
SIZE_T Length, HeaderLength, TotalLength;
|
|
NTSTATUS Status;
|
|
ULONG i;
|
|
|
|
/* Create the XML buffer and make sure it's OK */
|
|
Status = TranslateMachineInformationXML(&XmlBuffer, NULL);
|
|
CHECK_PARAMETER_WITH_STATUS(NT_SUCCESS(Status), Status);
|
|
CHECK_PARAMETER_WITH_STATUS(XmlBuffer, STATUS_UNSUCCESSFUL);
|
|
|
|
/* Compute the sizes and allocate a buffer for it */
|
|
Length = wcslen(XmlBuffer);
|
|
HeaderLength = strlen("MACHINEINFO");
|
|
TotalLength = HeaderLength +
|
|
Length +
|
|
sizeof(*BsBuffer) +
|
|
2 * sizeof(ANSI_NULL);
|
|
BsBuffer = SacAllocatePool(TotalLength, GLOBAL_BLOCK_TAG);
|
|
CHECK_PARAMETER_WITH_STATUS(BsBuffer, STATUS_NO_MEMORY);
|
|
|
|
/* Copy the XML property name */
|
|
strcpy((PCHAR)BsBuffer->Data, "MACHINEINFO");
|
|
BsBuffer->ValueIndex = HeaderLength + sizeof(ANSI_NULL);
|
|
|
|
/* Copy the data and NULL-terminate it */
|
|
for (i = 0; i < Length; i++)
|
|
{
|
|
BsBuffer->Data[BsBuffer->ValueIndex + i] = XmlBuffer[i];
|
|
}
|
|
BsBuffer->Data[BsBuffer->ValueIndex + i] = ANSI_NULL;
|
|
|
|
/* Let the OS save the buffer for later */
|
|
Status = HeadlessDispatch(HeadlessCmdSetBlueScreenData,
|
|
BsBuffer,
|
|
TotalLength,
|
|
NULL,
|
|
NULL);
|
|
|
|
/* Failure or not, we don't need this anymore */
|
|
SacFreePool(BsBuffer);
|
|
SacFreePool(XmlBuffer);
|
|
|
|
/* Return the result */
|
|
SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC Initialize Machine Information: Exiting.\n");
|
|
return Status;
|
|
}
|
|
|
|
VOID
|
|
NTAPI
|
|
FreeMachineInformation(VOID)
|
|
{
|
|
ASSERT(MachineInformation);
|
|
|
|
/* Free every cached string of machine information */
|
|
if (MachineInformation->MachineName) SacFreePool(MachineInformation);
|
|
if (MachineInformation->MachineGuid) SacFreePool(MachineInformation->MachineGuid);
|
|
if (MachineInformation->ProcessorArchitecture) SacFreePool(MachineInformation->ProcessorArchitecture);
|
|
if (MachineInformation->MajorVersion) SacFreePool(MachineInformation->MajorVersion);
|
|
if (MachineInformation->BuildNumber) SacFreePool(MachineInformation->BuildNumber);
|
|
if (MachineInformation->ProductType) SacFreePool(MachineInformation->ProductType);
|
|
if (MachineInformation->ServicePack) SacFreePool(MachineInformation->ServicePack);
|
|
}
|
|
|
|
BOOLEAN
|
|
NTAPI
|
|
VerifyEventWaitable(IN HANDLE Handle,
|
|
OUT PVOID *WaitObject,
|
|
OUT PVOID *ActualWaitObject)
|
|
{
|
|
PVOID Object;
|
|
NTSTATUS Status;
|
|
POBJECT_TYPE ObjectType;
|
|
|
|
/* Reference the object */
|
|
Status = ObReferenceObjectByHandle(Handle,
|
|
EVENT_ALL_ACCESS,
|
|
NULL,
|
|
KernelMode,
|
|
&Object,
|
|
NULL);
|
|
*WaitObject = Object;
|
|
if (!NT_SUCCESS(Status))
|
|
{
|
|
SAC_DBG(SAC_DBG_INIT, "SAC VerifyEventWaitable: Unable to reference event object (%lx)\n", Status);
|
|
return FALSE;
|
|
}
|
|
|
|
/* Check if the object itself is NOT being used */
|
|
ObjectType = OBJECT_TO_OBJECT_HEADER(Object)->Type;
|
|
if (ObjectType->TypeInfo.UseDefaultObject == FALSE)
|
|
{
|
|
/* Get the actual object that's being used for the wait */
|
|
*ActualWaitObject = (PVOID)((ULONG_PTR)Object +
|
|
(ULONG_PTR)ObjectType->DefaultObject);
|
|
return TRUE;
|
|
}
|
|
|
|
/* Drop the reference we took */
|
|
SAC_DBG(SAC_DBG_INIT, "SAC VerifyEventWaitable: event object not waitable!\n");
|
|
ObDereferenceObject(*WaitObject);
|
|
return FALSE;
|
|
}
|
|
|
|
NTSTATUS
|
|
NTAPI
|
|
SerialBufferGetChar(OUT PCHAR Char)
|
|
{
|
|
/* Check if nothing's been produced yet */
|
|
if (SerialPortConsumerIndex == SerialPortProducerIndex)
|
|
{
|
|
return STATUS_NO_DATA_DETECTED;
|
|
}
|
|
|
|
/* Consume the produced character and clear it*/
|
|
*Char = SerialPortBuffer[SerialPortConsumerIndex];
|
|
SerialPortBuffer[SerialPortConsumerIndex] = ANSI_NULL;
|
|
|
|
/* Advance the index and return success */
|
|
_InterlockedExchange(&SerialPortConsumerIndex,
|
|
(SerialPortConsumerIndex + 1) &
|
|
(SAC_SERIAL_PORT_BUFFER_SIZE - 1));
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
ULONG
|
|
NTAPI
|
|
GetMessageLineCount(IN ULONG MessageIndex)
|
|
{
|
|
ULONG LineCount = 0;
|
|
PWCHAR Buffer;
|
|
|
|
/* Get the message buffer */
|
|
Buffer = GetMessage(MessageIndex);
|
|
if (Buffer)
|
|
{
|
|
/* Scan it looking for new lines, and increment the count each time */
|
|
while (*Buffer) if (*Buffer++ == L'\n') ++LineCount;
|
|
}
|
|
|
|
/* Return the line count */
|
|
return LineCount;
|
|
}
|
|
|
|
ULONG
|
|
ConvertAnsiToUnicode(
|
|
IN PWCHAR pwch,
|
|
IN PCHAR pch,
|
|
IN ULONG length
|
|
)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
BOOLEAN
|
|
IsCmdEventRegistrationProcess(
|
|
IN PFILE_OBJECT FileObject
|
|
)
|
|
{
|
|
return FALSE;
|
|
}
|
|
|
|
NTSTATUS
|
|
InvokeUserModeService(
|
|
VOID
|
|
)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
TranslateMachineInformationText(
|
|
IN PWCHAR Buffer)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
CopyAndInsertStringAtInterval(
|
|
IN PWCHAR SourceStr,
|
|
IN ULONG Interval,
|
|
IN PWCHAR InsertStr,
|
|
OUT PWCHAR pDestStr
|
|
)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
RegisterSacCmdEvent(
|
|
IN PVOID Object,
|
|
IN PKEVENT SetupCmdEvent[]
|
|
)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|
|
|
|
NTSTATUS
|
|
UnregisterSacCmdEvent(
|
|
IN PFILE_OBJECT FileObject
|
|
)
|
|
{
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
}
|