/* * 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 /* 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"\r\n"); /* Do we have a machine name? */ if (MachineInformation->MachineName) { /* Go and add it in */ Size += wcslen(MachineInformation->MachineName); Size += wcslen(L"%s\r\n"); } /* Do we have a GUID? */ if (MachineInformation->MachineGuid) { /* Go and add it in */ Size += wcslen(MachineInformation->MachineGuid); Size += wcslen(L"%s\r\n"); } /* Do we know the processor? */ if (MachineInformation->ProcessorArchitecture) { /* Go and add it in */ Size += wcslen(MachineInformation->ProcessorArchitecture); Size += wcslen(L"%s\r\n"); } /* Do we have the version? */ if (MachineInformation->MajorVersion) { /* Go and add it in */ Size += wcslen(MachineInformation->MajorVersion); Size += wcslen(L"%s\r\n"); } /* Do we have the build? */ if (MachineInformation->BuildNumber) { /* Go and add it in */ Size += wcslen(MachineInformation->BuildNumber); Size += wcslen(L"%s\r\n"); } /* Do we have the product type? */ if (MachineInformation->ProductType) { /* Go and add it in */ Size += wcslen(MachineInformation->ProductType); Size += wcslen(L"%s\r\n"); } /* Do we have a service pack? */ if (MachineInformation->ServicePack) { /* Go and add it in */ Size += wcslen(MachineInformation->ServicePack); Size += wcslen(L"%s\r\n"); } /* Anything else we need to know? Add it in too */ if (ExtraData) Size += wcslen(ExtraData); /* Finally, add the footer */ Size += wcslen(L"\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"\r\n"); p += wcslen(L"\r\n"); if (MachineInformation->MachineName) { p += swprintf(p, L"%s\r\n", MachineInformation->MachineName); } if (MachineInformation->MachineGuid) { p += swprintf(p, L"%s\r\n", MachineInformation->MachineGuid); } if (MachineInformation->ProcessorArchitecture) { p += swprintf(p, L"%s\r\n", MachineInformation->ProcessorArchitecture); } if (MachineInformation->MajorVersion) { p += swprintf(p, L"%s\r\n", MachineInformation->MajorVersion); } if (MachineInformation->BuildNumber) { p += swprintf(p, L"%s\r\n", MachineInformation->BuildNumber); } if (MachineInformation->ProductType) { p += swprintf(p, L"%s\r\n", MachineInformation->ProductType); } if (MachineInformation->ServicePack) { p += swprintf(p, L"%s\r\n", MachineInformation->ServicePack); } if (ExtraData) { wcscpy(p, ExtraData); p += wcslen(ExtraData); } wcscpy(p, L"\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; }