NTSTATUS NTAPI VTUTF8ChannelDestroy(IN PSAC_CHANNEL Channel) { CHECK_PARAMETER(Channel); /* Free the buffer and then destroy the channel */ if (Channel->OBuffer) SacFreePool(Channel->OBuffer); if (Channel->IBuffer) SacFreePool(Channel->IBuffer); return ChannelDestroy(Channel); }
NTSTATUS NTAPI CreateDeviceSecurityDescriptor(IN PDEVICE_OBJECT *DeviceObject) { NTSTATUS Status; PSECURITY_DESCRIPTOR SecurityDescriptor; BOOLEAN MemoryAllocated = FALSE; PACL Dacl = NULL; PVOID ObjectSecurityDescriptor = NULL; SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC CreateDeviceSecurityDescriptor: Entering.\n"); /* Get the current SD of the device object */ Status = ObGetObjectSecurity(*DeviceObject, &SecurityDescriptor, &MemoryAllocated); if (!NT_SUCCESS(Status)) { SAC_DBG(SAC_DBG_INIT, "SAC: Unable to get security descriptor, error: %x\n", Status); NT_ASSERT(MemoryAllocated == FALSE); SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC CreateDeviceSecurityDescriptor: Exiting with status 0x%x\n", Status); return Status; } /* Build a DACL for it */ Status = BuildDeviceAcl(&Dacl); if (Status >= 0) { ASSERT(FALSE); } else { SAC_DBG(SAC_DBG_INIT, "SAC CreateDeviceSecurityDescriptor : Unable to create Raw ACL, error : %x\n", Status); /* FIXME: Temporary hack */ Status = STATUS_SUCCESS; goto CleanupPath; } CleanupPath: /* Release the SD we queried */ ObReleaseObjectSecurity(SecurityDescriptor, MemoryAllocated); /* Free anything else we may have allocated */ if (ObjectSecurityDescriptor) ExFreePool(ObjectSecurityDescriptor); if (Dacl) SacFreePool(Dacl); /* All done */ SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC CreateDeviceSecurityDescriptor: Exiting with status 0x%x\n", Status); return Status; }
VOID NTAPI FreeGlobalData(VOID) { UNICODE_STRING SymbolicLink; SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC FreeGlobalData: Entering.\n"); /* Only free if we allocated */ if (GlobalDataInitialized) { /* Close the SAC event if we had created one */ if (SACEvent) { ZwClose(SACEventHandle); SACEvent = NULL; } /* Destroy the cached messages */ TearDownGlobalMessageTable(); /* Delete the Win32 symbolic link */ RtlInitUnicodeString(&SymbolicLink, L"\\DosDevices\\SAC"); IoDeleteSymbolicLink(&SymbolicLink); /* Tear down connections */ ConMgrShutdown(); /* Tear down channels */ ChanMgrShutdown(); /* Free the serial port buffer */ if (SerialPortBuffer) SacFreePool(SerialPortBuffer); /* Free cached machine information */ FreeMachineInformation(); /* Cleanup the custom heap allocator */ FreeMemoryManagement(); /* We're back to a virgin state */ GlobalDataInitialized = FALSE; } /* All done */ SAC_DBG(SAC_DBG_ENTRY_EXIT, "SAC FreeGlobalData: Exiting.\n"); }
NTSTATUS NTAPI VTUTF8ChannelOFlush(IN PSAC_CHANNEL Channel) { NTSTATUS Status; PSAC_VTUTF8_SCREEN Screen; INT Color[2], Position[2]; ULONG Utf8ProcessedCount, Utf8Count, R, C, ForeColor, BackColor, Attribute; PWCHAR TmpBuffer; BOOLEAN Overflow = FALSE; CHECK_PARAMETER(Channel); /* Set the cell buffer position */ Screen = (PSAC_VTUTF8_SCREEN)Channel->OBuffer; /* Allocate a temporary buffer */ TmpBuffer = SacAllocatePool(40, GLOBAL_BLOCK_TAG); if (!TmpBuffer) { Status = STATUS_NO_MEMORY; goto Quickie; } /* First, clear the screen */ Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiClearScreen, NULL, 0); if (!NT_SUCCESS(Status)) goto Quickie; /* Next, reset the cursor position */ Position[1] = 0; Position[0] = 0; Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiSetPosition, Position, sizeof(Position)); if (!NT_SUCCESS(Status)) goto Quickie; /* Finally, reset the attributes */ Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiClearAttributes, NULL, 0); if (!NT_SUCCESS(Status)) goto Quickie; /* Now set the current cell attributes */ Attribute = Channel->CellFlags; Status = VTUTF8ChannelProcessAttributes(Channel, Attribute); if (!NT_SUCCESS(Status)) goto Quickie; /* And set the current cell colors */ ForeColor = Channel->CellForeColor; BackColor = Channel->CellBackColor; Color[1] = BackColor; Color[0] = ForeColor; Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiSetColors, Color, sizeof(Color)); if (!NT_SUCCESS(Status)) goto Quickie; /* Now loop all the characters in the cell buffer */ for (R = 0; R < SAC_VTUTF8_ROW_HEIGHT; R++) { /* Across every row */ for (C = 0; C < SAC_VTUTF8_COL_WIDTH; C++) { /* Check if there's been a change in colors */ if ((Screen->Cell[R][C].CellBackColor != BackColor) || (Screen->Cell[R][C].CellForeColor != ForeColor)) { /* New colors are being drawn -- are we also on a new row now? */ if (Overflow) { /* Reposition the cursor correctly */ Position[1] = R; Position[0] = C; Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiSetPosition, Position, sizeof(Position)); if (!NT_SUCCESS(Status)) goto Quickie; Overflow = FALSE; } /* Cache the new colors */ ForeColor = Screen->Cell[R][C].CellForeColor; BackColor = Screen->Cell[R][C].CellBackColor; /* Set them on the screen */ Color[1] = BackColor; Color[0] = ForeColor; Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiSetColors, Color, sizeof(Color)); if (!NT_SUCCESS(Status)) goto Quickie; } /* Check if there's been a change in attributes */ if (Screen->Cell[R][C].CellFlags != Attribute) { /* Yep! Are we also on a new row now? */ if (Overflow) { /* Reposition the cursor correctly */ Position[1] = R; Position[0] = C; Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiSetPosition, Position, sizeof(Position)); if (!NT_SUCCESS(Status)) goto Quickie; Overflow = FALSE; } /* Set the new attributes on screen */ Attribute = Screen->Cell[R][C].CellFlags; Status = VTUTF8ChannelProcessAttributes(Channel, Attribute); if (!NT_SUCCESS(Status)) goto Quickie; } /* Time to write the character -- are we on a new row now? */ if (Overflow) { /* Reposition the cursor correctly */ Position[1] = R; Position[0] = C; Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiSetPosition, Position, sizeof(Position)); if (!NT_SUCCESS(Status)) goto Quickie; Overflow = FALSE; } /* Write the character into our temporary buffer */ *TmpBuffer = Screen->Cell[R][C].Char; TmpBuffer[1] = UNICODE_NULL; /* Convert it to UTF-8 */ if (!SacTranslateUnicodeToUtf8(TmpBuffer, 1, Utf8ConversionBuffer, Utf8ConversionBufferSize, &Utf8Count, &Utf8ProcessedCount)) { /* Bail out if this failed */ Status = STATUS_UNSUCCESSFUL; goto Quickie; } /* Make sure we have a remaining valid character */ if (Utf8Count) { /* Write it out on the wire */ Status = ConMgrWriteData(Channel, Utf8ConversionBuffer, Utf8Count); if (!NT_SUCCESS(Status)) goto Quickie; } } /* All the characters on the row are done, indicate we need a reset */ Overflow = TRUE; } /* Everything is done, set the positition one last time */ Position[1] = Channel->CursorRow; Position[0] = Channel->CursorCol; Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiSetPosition, Position, sizeof(Position)); if (!NT_SUCCESS(Status)) goto Quickie; /* Set the current attribute one last time */ Status = VTUTF8ChannelProcessAttributes(Channel, Channel->CellFlags); if (!NT_SUCCESS(Status)) goto Quickie; /* Set the current colors one last time */ Color[1] = Channel->CellBackColor; Color[0] = Channel->CellForeColor; Status = VTUTF8ChannelAnsiDispatch(Channel, SacAnsiSetColors, Color, sizeof(Color)); if (!NT_SUCCESS(Status)) goto Quickie; /* Flush all the data out on the wire */ Status = ConMgrFlushData(Channel); Quickie: /* We're done, free the temporary buffer */ if (TmpBuffer) SacFreePool(TmpBuffer); /* Indicate that all new data has been flushed now */ if (NT_SUCCESS(Status)) { _InterlockedExchange(&Channel->ChannelHasNewOBufferData, 0); } /* Return the result */ return Status; }
NTSTATUS NTAPI VTUTF8ChannelAnsiDispatch(IN PSAC_CHANNEL Channel, IN SAC_ANSI_DISPATCH AnsiCode, IN INT* Data, IN ULONG Length) { NTSTATUS Status = STATUS_SUCCESS; PCHAR LocalBuffer = NULL, Tmp; INT l; CHECK_PARAMETER1(Channel); /* Check which ANSI sequence we should output */ switch (AnsiCode) { /* Send the [2J (Clear Screen and Reset Cursor) */ case SacAnsiClearScreen: Tmp = "\x1B[2J"; break; /* Send the [0J (Clear From Position Till End Of Screen) */ case SacAnsiClearEndOfScreen: Tmp = "\x1B[0J"; break; /* Send the [0K (Clear from Position Till End Of Line) */ case SacAnsiClearEndOfLine: Tmp = "\x1B[0K"; break; /* Send a combination of two [#m attribute changes */ case SacAnsiSetColors: /* Allocate a small local buffer for it */ LocalBuffer = SacAllocatePool(SAC_VTUTF8_COL_WIDTH, GLOBAL_BLOCK_TAG); CHECK_ALLOCATION(LocalBuffer); /* Caller should have sent two colors as two integers */ if (!(Data) || (Length != 8)) { Status = STATUS_INVALID_PARAMETER; break; } /* Create the escape sequence string */ l = sprintf(LocalBuffer, "\x1B[%dm\x1B[%dm", Data[1], Data[0]); ASSERT((l + 1)*sizeof(UCHAR) < SAC_VTUTF8_COL_WIDTH); ASSERT(LocalBuffer); Tmp = LocalBuffer; break; /* Send the [#;#H (Cursor Position) sequence */ case SacAnsiSetPosition: /* Allocate a small local buffer for it */ LocalBuffer = SacAllocatePool(SAC_VTUTF8_COL_WIDTH, GLOBAL_BLOCK_TAG); CHECK_ALLOCATION(LocalBuffer); /* Caller should have sent the position as two integers */ if (!(Data) || (Length != 8)) { Status = STATUS_INVALID_PARAMETER; break; } /* Create the escape sequence string */ l = sprintf(LocalBuffer, "\x1B[%d;%dH", Data[1] + 1, Data[0] + 1); ASSERT((l + 1)*sizeof(UCHAR) < SAC_VTUTF8_COL_WIDTH); ASSERT(LocalBuffer); Tmp = LocalBuffer; break; /* Send the [0m sequence (Set Attribute 0) */ case SacAnsiClearAttributes: Tmp = "\x1B[0m"; break; /* Send the [7m sequence (Set Attribute 7) */ case SacAnsiSetInverseAttribute: Tmp = "\x1B[7m"; break; /* Send the [27m sequence (Set Attribute 27) */ case SacAnsiClearInverseAttribute: Tmp = "\x1B[27m"; break; /* Send the [5m sequence (Set Attribute 5) */ case SacAnsiSetBlinkAttribute: Tmp = "\x1B[5m"; break; /* Send the [25m sequence (Set Attribute 25) */ case SacAnsiClearBlinkAttribute: Tmp = "\x1B[25m"; break; /* Send the [1m sequence (Set Attribute 1) */ case SacAnsiSetBoldAttribute: Tmp = "\x1B[1m"; break; /* Send the [22m sequence (Set Attribute 22) */ case SacAnsiClearBoldAttribute: Tmp = "\x1B[22m"; break; /* We don't recognize it */ default: Status = STATUS_INVALID_PARAMETER; break; } /* Did everything work above? */ if (NT_SUCCESS(Status)) { /* Go write out the sequence */ Status = ConMgrWriteData(Channel, Tmp, strlen(Tmp)); if (NT_SUCCESS(Status)) { /* Now flush it */ Status = ConMgrFlushData(Channel); } } /* Free the temporary buffer, if any, and return the status */ if (LocalBuffer) SacFreePool(LocalBuffer); return Status; }
BOOLEAN NTAPI InitializeGlobalData(IN PUNICODE_STRING RegistryPath, IN PDRIVER_OBJECT DriverObject) { NTSTATUS Status; UNICODE_STRING LinkName; UNICODE_STRING DeviceName; UNICODE_STRING EventName; PAGED_CODE(); SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering.\n"); /* If we already did this, bail out */ if (GlobalDataInitialized) goto SuccessExit; /* Setup the symbolic link for Win32 support */ RtlInitUnicodeString(&LinkName, L"\\DosDevices\\SAC"); RtlInitUnicodeString(&DeviceName, L"\\Device\\SAC"); Status = IoCreateSymbolicLink(&LinkName, &DeviceName); if (!NT_SUCCESS(Status)) return FALSE; /* Initialize the internal heap manager */ if (!InitializeMemoryManagement()) { IoDeleteSymbolicLink(&LinkName); SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with status FALSE\n"); return FALSE; } /* Preload the messages in memory */ Status = PreloadGlobalMessageTable(DriverObject->DriverStart); if (!NT_SUCCESS(Status)) { IoDeleteSymbolicLink(&LinkName); SAC_DBG(SAC_DBG_INIT, "unable to pre-load message table: %X\n", Status); return FALSE; } /* Check if the administrator enabled this */ Status = GetCommandConsoleLaunchingPermission(&CommandConsoleLaunchingEnabled); if (!NT_SUCCESS(Status)) { /* Is it enabled? */ if (CommandConsoleLaunchingEnabled) { /* Set the service start type to the correct value */ Status = ImposeSacCmdServiceStartTypePolicy(); if (!NT_SUCCESS(Status)) { SAC_DBG(SAC_DBG_INIT, "failed ImposeSacCmdServiceStartTypePolicy: %X\n", Status); } } /* We're going to keep going with the default */ SAC_DBG(SAC_DBG_INIT, "failed GetCommandConsoleLaunchingPermission: %X\n", Status); } /* Allocate the UTF-8 Conversion Buffer */ Utf8ConversionBuffer = SacAllocatePool(Utf8ConversionBufferSize, GLOBAL_BLOCK_TAG); if (!Utf8ConversionBuffer) { /* Handle failure case */ TearDownGlobalMessageTable(); IoDeleteSymbolicLink(&LinkName); SAC_DBG(SAC_DBG_INIT, "unable to allocate memory for UTF8 translation\n"); return FALSE; } /* Initialize the channel manager */ Status = ChanMgrInitialize(); if (!NT_SUCCESS(Status)) { /* Handle failure case */ SacFreePool(Utf8ConversionBuffer); TearDownGlobalMessageTable(); IoDeleteSymbolicLink(&LinkName); SAC_DBG(SAC_DBG_INIT, "Failed to create SAC Channel\n"); return FALSE; } /* Allocate the serial port buffer */ SerialPortBuffer = SacAllocatePool(SAC_SERIAL_PORT_BUFFER_SIZE, GLOBAL_BLOCK_TAG); if (!SerialPortBuffer) { /* Handle failure case */ SacFreePool(Utf8ConversionBuffer); TearDownGlobalMessageTable(); IoDeleteSymbolicLink(&LinkName); SAC_DBG(SAC_DBG_INIT, "Failed to allocate Serial Port Buffer\n"); return FALSE; } /* Zero it out */ RtlZeroMemory(SerialPortBuffer, SAC_SERIAL_PORT_BUFFER_SIZE); /* Initialize command events. After this, driver data is good to go */ KeInitializeMutex(&SACCMDEventInfoMutex, FALSE); InitializeCmdEventInfo(); GlobalDataInitialized = TRUE; ProcessingType = 0; IoctlSubmitted = 0; /* Create the SAC event */ RtlInitUnicodeString(&EventName, L"\\SACEvent"); SACEvent = IoCreateSynchronizationEvent(&EventName, &SACEventHandle); if (!SACEvent) { /* Handle failure case */ SacFreePool(Utf8ConversionBuffer); TearDownGlobalMessageTable(); IoDeleteSymbolicLink(&LinkName); SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with event NULL\n"); return FALSE; } /* Cache machine information */ InitializeMachineInformation(); /* Register it */ Status = RegisterBlueScreenMachineInformation(); if (!NT_SUCCESS(Status)) { /* Handle failure case */ SacFreePool(Utf8ConversionBuffer); TearDownGlobalMessageTable(); IoDeleteSymbolicLink(&LinkName); SAC_DBG(SAC_DBG_INIT, "Failed to register blue screen machine info\n"); return FALSE; } SuccessExit: /* Success path -- everything worked */ SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with status TRUE\n"); return TRUE; }
BOOLEAN NTAPI InitializeDeviceData(IN PDEVICE_OBJECT DeviceObject) { PSAC_DEVICE_EXTENSION DeviceExtension = DeviceObject->DeviceExtension; BOOLEAN EnableData; ULONG PriorityValue; NTSTATUS Status; LARGE_INTEGER DueTime; PWCHAR Message; PAGED_CODE(); SAC_DBG(SAC_DBG_ENTRY_EXIT, "Entering.\n"); /* If we already did this, bail out */ if (DeviceExtension->Initialized) goto SuccessExit; /* Setup the DO flags */ DeviceObject->Flags |= DO_DIRECT_IO; DeviceObject->StackSize = 16; /* Setup the device extension */ DeviceExtension->DeviceObject = DeviceObject; DeviceExtension->PriorityBoost = IO_SERIAL_INCREMENT; DeviceExtension->PriorityFail = 0; DeviceExtension->RundownInProgress = 0; /* Initialize locks, events, timers, DPCs, etc... */ KeInitializeTimer(&DeviceExtension->Timer); KeInitializeDpc(&DeviceExtension->Dpc, TimerDpcRoutine, DeviceExtension); KeInitializeSpinLock(&DeviceExtension->Lock); KeInitializeEvent(&DeviceExtension->Event, SynchronizationEvent, FALSE); InitializeListHead(&DeviceExtension->List); /* Attempt to enable HDL support */ EnableData = TRUE; Status = HeadlessDispatch(HeadlessCmdEnableTerminal, &EnableData, sizeof(EnableData), NULL, 0); if (!NT_SUCCESS(Status)) { /* Bail out if we couldn't even get this far */ SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting (1) with status FALSE\n"); return FALSE; } /* Remember which process we started in */ DeviceExtension->Process = IoGetCurrentProcess(); /* Protect the device against non-admins */ Status = CreateDeviceSecurityDescriptor(&DeviceExtension->DeviceObject); if (!NT_SUCCESS(Status)) { /* Write down why we failed */ SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting (2) with status FALSE\n"); /* Disable the HDL terminal on failure */ EnableData = FALSE; Status = HeadlessDispatch(HeadlessCmdEnableTerminal, &EnableData, sizeof(EnableData), NULL, NULL); if (!NT_SUCCESS(Status)) SAC_DBG(SAC_DBG_INIT, "Failed dispatch\n"); /* Bail out */ return FALSE; } /* Create the worker thread */ Status = PsCreateSystemThread(&DeviceExtension->WorkerThreadHandle, THREAD_ALL_ACCESS, NULL, NULL, NULL, WorkerThreadStartUp, DeviceExtension); if (!NT_SUCCESS(Status)) { /* Write down why we failed */ SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting (3) with status FALSE\n"); /* Disable the HDL terminal on failure */ EnableData = FALSE; Status = HeadlessDispatch(HeadlessCmdEnableTerminal, &EnableData, sizeof(EnableData), NULL, NULL); if (!NT_SUCCESS(Status)) SAC_DBG(SAC_DBG_INIT, "Failed dispatch\n"); /* Bail out */ return FALSE; } /* Set the priority of our thread to highest */ PriorityValue = HIGH_PRIORITY; Status = NtSetInformationThread(DeviceExtension->WorkerThreadHandle, ThreadPriority, &PriorityValue, sizeof(PriorityValue)); if (!NT_SUCCESS(Status)) { /* For debugging, write down why we failed */ SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting (6) with status FALSE\n"); DeviceExtension->PriorityFail = TRUE; /* Initialize rundown and wait for the thread to do it */ KeInitializeEvent(&DeviceExtension->RundownEvent, SynchronizationEvent, FALSE); KeSetEvent(&DeviceExtension->Event, DeviceExtension->PriorityBoost, FALSE); Status = KeWaitForSingleObject(&DeviceExtension->RundownEvent, Executive, KernelMode, FALSE, NULL); ASSERT(Status == STATUS_SUCCESS); /* Disable the HDL terminal on failure */ EnableData = FALSE; Status = HeadlessDispatch(HeadlessCmdEnableTerminal, &EnableData, sizeof(EnableData), NULL, 0); if (!NT_SUCCESS(Status)) SAC_DBG(SAC_DBG_INIT, "Failed dispatch\n"); /* Bail out */ return FALSE; } /* The first "packet" is the machine information in XML... */ Status = TranslateMachineInformationXML(&Message, NULL); if (NT_SUCCESS(Status)) { /* Go ahead and send it */ UTF8EncodeAndSend(L"<?xml version=\"1.0\"?>\r\n"); UTF8EncodeAndSend(Message); /* Free the temporary buffer */ SacFreePool(Message); } /* Finally, initialize the I/O Manager */ Status = ConMgrInitialize(); if (!NT_SUCCESS(Status)) return FALSE; /* Set the timer. Once this is done, the device is initialized */ DueTime.QuadPart = -4000; KeSetTimerEx(&DeviceExtension->Timer, DueTime, 4, &DeviceExtension->Dpc); DeviceExtension->Initialized = TRUE; SuccessExit: /* Success path -- everything worked */ SAC_DBG(SAC_DBG_ENTRY_EXIT, "Exiting with status TRUE\n"); return TRUE; }