NTSTATUS NTAPI RawChannelCreate(IN PSAC_CHANNEL Channel) { CHECK_PARAMETER(Channel); /* Allocate the output buffer */ Channel->OBuffer = SacAllocatePool(SAC_RAW_OBUFFER_SIZE, GLOBAL_BLOCK_TAG); CHECK_ALLOCATION(Channel->OBuffer); /* Allocate the input buffer */ Channel->IBuffer = SacAllocatePool(SAC_RAW_IBUFFER_SIZE, GLOBAL_BLOCK_TAG); CHECK_ALLOCATION(Channel->IBuffer); /* Reset all flags and return success */ Channel->OBufferIndex = 0; Channel->OBufferFirstGoodIndex = 0; Channel->ChannelHasNewIBufferData = FALSE; Channel->ChannelHasNewOBufferData = FALSE; return STATUS_SUCCESS; }
NTSTATUS NTAPI VTUTF8ChannelCreate(IN PSAC_CHANNEL Channel) { NTSTATUS Status; CHECK_PARAMETER(Channel); /* Allocate the output buffer */ Channel->OBuffer = SacAllocatePool(SAC_VTUTF8_OBUFFER_SIZE, GLOBAL_BLOCK_TAG); CHECK_ALLOCATION(Channel->OBuffer); /* Allocate the input buffer */ Channel->IBuffer = SacAllocatePool(SAC_VTUTF8_IBUFFER_SIZE, GLOBAL_BLOCK_TAG); CHECK_ALLOCATION(Channel->IBuffer); /* Initialize the output stream */ Status = VTUTF8ChannelOInit(Channel); if (NT_SUCCESS(Status)) return Status; /* Reset all flags and return success */ _InterlockedExchange(&Channel->ChannelHasNewOBufferData, 0); _InterlockedExchange(&Channel->ChannelHasNewIBufferData, 0); return STATUS_SUCCESS; }
NTSTATUS NTAPI ChannelGetDescription(IN PSAC_CHANNEL Channel, IN PWCHAR* Description) { CHECK_PARAMETER1(Channel); CHECK_PARAMETER2(Description); /* Allocate space to hold the description */ *Description = SacAllocatePool(sizeof(Channel->DescriptionBuffer), GLOBAL_BLOCK_TAG); CHECK_ALLOCATION(*Description); /* Lock the attributes while we copy the name */ ChannelLockAttributes(Channel); /* Copy the name and null-terminate it */ ASSERT(((wcslen(Channel->DescriptionBuffer) + 1) * sizeof(WCHAR)) <= ((SAC_CHANNEL_DESCRIPTION_SIZE + 1) * sizeof(WCHAR))); wcsncpy(*Description, Channel->DescriptionBuffer, RTL_NUMBER_OF(Channel->DescriptionBuffer)); // bug (*Description)[SAC_CHANNEL_DESCRIPTION_SIZE] = UNICODE_NULL; /* Release the lock and return */ ChannelUnlockAttributes(Channel); return STATUS_SUCCESS; }
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; }