2010-05-31 06:28:55 +00:00
|
|
|
/*
|
2012-10-25 20:40:41 +00:00
|
|
|
* COPYRIGHT: See COPYING in the top level directory
|
|
|
|
* PROJECT: ReactOS Console Server DLL
|
2015-10-05 12:21:25 +00:00
|
|
|
* FILE: win32ss/user/winsrv/consrv/console.c
|
2013-04-07 23:18:59 +00:00
|
|
|
* PURPOSE: Console Management Functions
|
2023-08-18 17:06:20 +00:00
|
|
|
* PROGRAMMERS: Gé van Geldorp
|
2013-04-10 20:22:30 +00:00
|
|
|
* Jeffrey Morlan
|
|
|
|
* Hermes Belusca-Maito (hermes.belusca@sfr.fr)
|
2010-05-31 06:28:55 +00:00
|
|
|
*/
|
|
|
|
|
2013-03-19 22:05:38 +00:00
|
|
|
/* INCLUDES *******************************************************************/
|
2010-05-31 06:28:55 +00:00
|
|
|
|
2012-10-23 22:31:36 +00:00
|
|
|
#include "consrv.h"
|
2014-02-04 19:54:42 +00:00
|
|
|
|
2014-09-07 22:53:49 +00:00
|
|
|
/* This is for COM usage */
|
|
|
|
#define COBJMACROS
|
|
|
|
#include <shlobj.h>
|
|
|
|
|
2022-01-14 21:00:55 +00:00
|
|
|
#include "../concfg/font.h"
|
2014-05-04 00:01:48 +00:00
|
|
|
#include <alias.h>
|
2014-08-29 19:45:45 +00:00
|
|
|
#include <history.h>
|
2013-04-07 23:18:59 +00:00
|
|
|
#include "procinit.h"
|
2013-03-24 17:08:10 +00:00
|
|
|
|
2013-03-30 18:44:56 +00:00
|
|
|
#define NDEBUG
|
2010-05-31 06:28:55 +00:00
|
|
|
#include <debug.h>
|
|
|
|
|
2014-05-02 16:46:13 +00:00
|
|
|
|
2013-06-23 00:18:47 +00:00
|
|
|
/* GLOBALS ********************************************************************/
|
2012-10-23 22:31:36 +00:00
|
|
|
|
2020-04-10 18:37:28 +00:00
|
|
|
// static ULONG CurrentConsoleID = 0;
|
|
|
|
|
2014-09-05 21:12:42 +00:00
|
|
|
/* The list of the ConSrv consoles */
|
2014-05-04 00:01:48 +00:00
|
|
|
static ULONG ConsoleListSize;
|
2014-09-05 21:12:42 +00:00
|
|
|
static PCONSRV_CONSOLE* ConsoleList;
|
2020-04-10 18:37:28 +00:00
|
|
|
// static LIST_ENTRY ConDrvConsoleList;
|
2014-05-04 00:01:48 +00:00
|
|
|
static RTL_RESOURCE ListLock;
|
|
|
|
|
|
|
|
#define ConSrvLockConsoleListExclusive() \
|
|
|
|
RtlAcquireResourceExclusive(&ListLock, TRUE)
|
|
|
|
|
|
|
|
#define ConSrvLockConsoleListShared() \
|
|
|
|
RtlAcquireResourceShared(&ListLock, TRUE)
|
|
|
|
|
|
|
|
#define ConSrvUnlockConsoleList() \
|
|
|
|
RtlReleaseResource(&ListLock)
|
|
|
|
|
2020-04-10 18:37:28 +00:00
|
|
|
#if 0
|
|
|
|
static NTSTATUS
|
|
|
|
ConDrvInsertConsole(
|
|
|
|
IN PCONSOLE Console)
|
|
|
|
{
|
|
|
|
ASSERT(Console);
|
|
|
|
|
|
|
|
/* All went right, so add the console to the list */
|
|
|
|
ConSrvLockConsoleListExclusive();
|
|
|
|
|
|
|
|
DPRINT("Insert in the list\n");
|
|
|
|
InsertTailList(&ConDrvConsoleList, &Console->ListEntry);
|
|
|
|
|
|
|
|
// FIXME: Move this code to the caller function!!
|
|
|
|
/* Get a new console ID */
|
|
|
|
_InterlockedExchange((PLONG)&Console->ConsoleID, CurrentConsoleID);
|
|
|
|
_InterlockedIncrement((PLONG)&CurrentConsoleID);
|
|
|
|
|
|
|
|
/* Unlock the console list and return success */
|
|
|
|
ConSrvUnlockConsoleList();
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
#endif
|
2014-05-04 00:01:48 +00:00
|
|
|
|
|
|
|
static NTSTATUS
|
2020-04-10 18:37:28 +00:00
|
|
|
InsertConsole(
|
|
|
|
OUT PHANDLE Handle,
|
|
|
|
IN PCONSRV_CONSOLE Console)
|
2014-05-04 00:01:48 +00:00
|
|
|
{
|
|
|
|
#define CONSOLE_HANDLES_INCREMENT 2 * 3
|
|
|
|
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
ULONG i = 0;
|
2014-08-12 14:59:13 +00:00
|
|
|
PCONSRV_CONSOLE* Block;
|
2014-05-04 00:01:48 +00:00
|
|
|
|
|
|
|
ASSERT( (ConsoleList == NULL && ConsoleListSize == 0) ||
|
|
|
|
(ConsoleList != NULL && ConsoleListSize != 0) );
|
|
|
|
|
|
|
|
/* All went right, so add the console to the list */
|
|
|
|
ConSrvLockConsoleListExclusive();
|
2014-11-08 22:19:07 +00:00
|
|
|
DPRINT("Insert in the list\n");
|
2014-05-04 00:01:48 +00:00
|
|
|
|
|
|
|
if (ConsoleList)
|
|
|
|
{
|
|
|
|
for (i = 0; i < ConsoleListSize; i++)
|
|
|
|
{
|
|
|
|
if (ConsoleList[i] == NULL) break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (i >= ConsoleListSize)
|
|
|
|
{
|
2014-11-08 22:19:07 +00:00
|
|
|
DPRINT("Creation of a new handles table\n");
|
2014-05-04 00:01:48 +00:00
|
|
|
/* Allocate a new handles table */
|
|
|
|
Block = ConsoleAllocHeap(HEAP_ZERO_MEMORY,
|
|
|
|
(ConsoleListSize +
|
2014-08-12 14:59:13 +00:00
|
|
|
CONSOLE_HANDLES_INCREMENT) * sizeof(PCONSRV_CONSOLE));
|
2014-05-04 00:01:48 +00:00
|
|
|
if (Block == NULL)
|
|
|
|
{
|
|
|
|
Status = STATUS_UNSUCCESSFUL;
|
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* If we previously had a handles table, free it and use the new one */
|
|
|
|
if (ConsoleList)
|
|
|
|
{
|
|
|
|
/* Copy the handles from the old table to the new one */
|
|
|
|
RtlCopyMemory(Block,
|
|
|
|
ConsoleList,
|
2014-08-12 14:59:13 +00:00
|
|
|
ConsoleListSize * sizeof(PCONSRV_CONSOLE));
|
2014-05-04 00:01:48 +00:00
|
|
|
ConsoleFreeHeap(ConsoleList);
|
|
|
|
}
|
|
|
|
ConsoleList = Block;
|
|
|
|
ConsoleListSize += CONSOLE_HANDLES_INCREMENT;
|
|
|
|
}
|
|
|
|
|
|
|
|
ConsoleList[i] = Console;
|
|
|
|
*Handle = ULongToHandle((i << 2) | 0x3);
|
|
|
|
|
|
|
|
Quit:
|
|
|
|
/* Unlock the console list and return status */
|
|
|
|
ConSrvUnlockConsoleList();
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Unused */
|
|
|
|
#if 0
|
|
|
|
static NTSTATUS
|
|
|
|
RemoveConsoleByHandle(IN HANDLE Handle)
|
|
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2014-08-12 14:59:13 +00:00
|
|
|
PCONSRV_CONSOLE Console;
|
2014-05-04 00:01:48 +00:00
|
|
|
|
|
|
|
BOOLEAN ValidHandle = ((HandleToULong(Handle) & 0x3) == 0x3);
|
|
|
|
ULONG Index = HandleToULong(Handle) >> 2;
|
|
|
|
|
|
|
|
if (!ValidHandle) return STATUS_INVALID_HANDLE;
|
|
|
|
|
|
|
|
ASSERT( (ConsoleList == NULL && ConsoleListSize == 0) ||
|
|
|
|
(ConsoleList != NULL && ConsoleListSize != 0) );
|
|
|
|
|
|
|
|
/* Remove the console from the list */
|
|
|
|
ConSrvLockConsoleListExclusive();
|
|
|
|
|
|
|
|
if (Index >= ConsoleListSize ||
|
|
|
|
(Console = ConsoleList[Index]) == NULL)
|
|
|
|
{
|
|
|
|
Status = STATUS_INVALID_HANDLE;
|
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
|
|
|
ConsoleList[Index] = NULL;
|
|
|
|
|
|
|
|
Quit:
|
|
|
|
/* Unlock the console list and return status */
|
|
|
|
ConSrvUnlockConsoleList();
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static NTSTATUS
|
2014-08-12 14:59:13 +00:00
|
|
|
RemoveConsoleByPointer(IN PCONSRV_CONSOLE Console)
|
2014-05-04 00:01:48 +00:00
|
|
|
{
|
|
|
|
ULONG i = 0;
|
|
|
|
|
|
|
|
if (!Console) return STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
ASSERT( (ConsoleList == NULL && ConsoleListSize == 0) ||
|
|
|
|
(ConsoleList != NULL && ConsoleListSize != 0) );
|
|
|
|
|
|
|
|
/* Remove the console from the list */
|
|
|
|
ConSrvLockConsoleListExclusive();
|
|
|
|
|
|
|
|
if (ConsoleList)
|
|
|
|
{
|
|
|
|
for (i = 0; i < ConsoleListSize; i++)
|
|
|
|
{
|
|
|
|
if (ConsoleList[i] == Console) ConsoleList[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-05 21:12:42 +00:00
|
|
|
/* Unlock the console list and return */
|
2014-05-04 00:01:48 +00:00
|
|
|
ConSrvUnlockConsoleList();
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2020-04-10 18:37:28 +00:00
|
|
|
#if 0
|
|
|
|
static NTSTATUS
|
|
|
|
RemoveConsole(IN PCONSOLE Console)
|
2014-05-04 00:01:48 +00:00
|
|
|
{
|
2020-04-10 18:37:28 +00:00
|
|
|
// ASSERT(Console);
|
|
|
|
if (!Console) return STATUS_INVALID_PARAMETER;
|
2014-05-04 00:01:48 +00:00
|
|
|
|
2020-04-10 18:37:28 +00:00
|
|
|
/* Remove the console from the list */
|
|
|
|
ConSrvLockConsoleListExclusive();
|
2014-05-04 00:01:48 +00:00
|
|
|
|
2020-04-10 18:37:28 +00:00
|
|
|
RemoveEntryList(&Console->ListEntry);
|
2014-05-04 00:01:48 +00:00
|
|
|
|
2020-04-10 18:37:28 +00:00
|
|
|
/* Unlock the console list and return success */
|
2014-05-04 00:01:48 +00:00
|
|
|
ConSrvUnlockConsoleList();
|
2020-04-10 18:37:28 +00:00
|
|
|
return STATUS_SUCCESS;
|
2014-05-04 00:01:48 +00:00
|
|
|
}
|
2020-04-10 18:37:28 +00:00
|
|
|
#endif
|
2014-05-04 00:01:48 +00:00
|
|
|
|
|
|
|
|
2013-06-23 00:18:47 +00:00
|
|
|
/* PRIVATE FUNCTIONS **********************************************************/
|
2013-01-24 22:41:33 +00:00
|
|
|
|
2014-09-07 22:53:49 +00:00
|
|
|
// Adapted from reactos/lib/rtl/unicode.c, RtlCreateUnicodeString line 2180
|
|
|
|
static BOOLEAN
|
|
|
|
ConsoleCreateUnicodeString(IN OUT PUNICODE_STRING UniDest,
|
|
|
|
IN PCWSTR Source)
|
|
|
|
{
|
|
|
|
SIZE_T Size = (wcslen(Source) + 1) * sizeof(WCHAR);
|
|
|
|
if (Size > MAXUSHORT) return FALSE;
|
|
|
|
|
|
|
|
UniDest->Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Size);
|
|
|
|
if (UniDest->Buffer == NULL) return FALSE;
|
|
|
|
|
|
|
|
RtlCopyMemory(UniDest->Buffer, Source, Size);
|
|
|
|
UniDest->MaximumLength = (USHORT)Size;
|
|
|
|
UniDest->Length = (USHORT)Size - sizeof(WCHAR);
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Adapted from reactos/lib/rtl/unicode.c, RtlFreeUnicodeString line 431
|
|
|
|
static VOID
|
|
|
|
ConsoleFreeUnicodeString(IN PUNICODE_STRING UnicodeString)
|
|
|
|
{
|
|
|
|
if (UnicodeString->Buffer)
|
|
|
|
{
|
|
|
|
ConsoleFreeHeap(UnicodeString->Buffer);
|
|
|
|
RtlZeroMemory(UnicodeString, sizeof(UNICODE_STRING));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-24 22:41:33 +00:00
|
|
|
|
2020-04-10 18:37:28 +00:00
|
|
|
/* CONSOLE VALIDATION FUNCTIONS ***********************************************/
|
|
|
|
|
|
|
|
BOOLEAN NTAPI
|
|
|
|
ConSrvValidateConsole(OUT PCONSRV_CONSOLE* Console,
|
|
|
|
IN HANDLE ConsoleHandle,
|
|
|
|
IN CONSOLE_STATE ExpectedState,
|
|
|
|
IN BOOLEAN LockConsole)
|
2013-01-24 22:41:33 +00:00
|
|
|
{
|
2020-04-10 18:37:28 +00:00
|
|
|
BOOLEAN RetVal = FALSE;
|
|
|
|
PCONSRV_CONSOLE ValidatedConsole;
|
2013-01-24 22:41:33 +00:00
|
|
|
|
2020-04-10 18:37:28 +00:00
|
|
|
BOOLEAN ValidHandle = ((HandleToULong(ConsoleHandle) & 0x3) == 0x3);
|
|
|
|
ULONG Index = HandleToULong(ConsoleHandle) >> 2;
|
2013-01-24 22:41:33 +00:00
|
|
|
|
2020-04-10 18:37:28 +00:00
|
|
|
if (!ValidHandle) return FALSE;
|
|
|
|
|
|
|
|
if (!Console) return FALSE;
|
|
|
|
*Console = NULL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Forbid creation or deletion of consoles when
|
|
|
|
* checking for the existence of a console.
|
|
|
|
*/
|
|
|
|
ConSrvLockConsoleListShared();
|
|
|
|
|
|
|
|
if (Index >= ConsoleListSize ||
|
|
|
|
(ValidatedConsole = ConsoleList[Index]) == NULL)
|
|
|
|
{
|
|
|
|
/* Unlock the console list and return */
|
|
|
|
ConSrvUnlockConsoleList();
|
|
|
|
return FALSE;
|
2013-01-24 22:41:33 +00:00
|
|
|
}
|
2020-04-10 18:37:28 +00:00
|
|
|
|
|
|
|
ValidatedConsole = ConsoleList[Index];
|
|
|
|
|
|
|
|
/* Unlock the console list */
|
|
|
|
ConSrvUnlockConsoleList();
|
|
|
|
|
|
|
|
RetVal = ConDrvValidateConsoleUnsafe((PCONSOLE)ValidatedConsole,
|
|
|
|
ExpectedState,
|
|
|
|
LockConsole);
|
|
|
|
if (RetVal) *Console = ValidatedConsole;
|
|
|
|
|
|
|
|
return RetVal;
|
2010-05-31 06:28:55 +00:00
|
|
|
}
|
2013-04-07 23:18:59 +00:00
|
|
|
|
2014-05-02 16:46:13 +00:00
|
|
|
NTSTATUS
|
2014-05-04 00:01:48 +00:00
|
|
|
ConSrvGetConsole(IN PCONSOLE_PROCESS_DATA ProcessData,
|
2014-08-12 14:59:13 +00:00
|
|
|
OUT PCONSRV_CONSOLE* Console,
|
2014-05-04 00:01:48 +00:00
|
|
|
IN BOOLEAN LockConsole)
|
2013-04-07 23:18:59 +00:00
|
|
|
{
|
2014-05-04 00:01:48 +00:00
|
|
|
NTSTATUS Status = STATUS_INVALID_HANDLE;
|
2014-08-12 14:59:13 +00:00
|
|
|
PCONSRV_CONSOLE GrabConsole;
|
2013-04-07 23:18:59 +00:00
|
|
|
|
2014-05-04 00:01:48 +00:00
|
|
|
// if (Console == NULL) return STATUS_INVALID_PARAMETER;
|
2013-06-23 00:18:47 +00:00
|
|
|
ASSERT(Console);
|
|
|
|
*Console = NULL;
|
|
|
|
|
2014-05-04 00:01:48 +00:00
|
|
|
if (ConSrvValidateConsole(&GrabConsole,
|
|
|
|
ProcessData->ConsoleHandle,
|
|
|
|
CONSOLE_RUNNING,
|
|
|
|
LockConsole))
|
|
|
|
{
|
2020-02-22 22:19:45 +00:00
|
|
|
_InterlockedIncrement(&GrabConsole->ReferenceCount);
|
2014-05-04 00:01:48 +00:00
|
|
|
*Console = GrabConsole;
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
}
|
2013-04-07 23:18:59 +00:00
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2014-05-02 16:46:13 +00:00
|
|
|
VOID
|
2014-08-12 14:59:13 +00:00
|
|
|
ConSrvReleaseConsole(IN PCONSRV_CONSOLE Console,
|
2018-06-10 01:23:01 +00:00
|
|
|
IN BOOLEAN IsConsoleLocked)
|
2013-04-07 23:18:59 +00:00
|
|
|
{
|
2014-05-04 00:01:48 +00:00
|
|
|
LONG RefCount = 0;
|
|
|
|
|
|
|
|
if (!Console) return;
|
|
|
|
// if (Console->ReferenceCount == 0) return; // This shouldn't happen
|
|
|
|
ASSERT(Console->ReferenceCount > 0);
|
|
|
|
|
|
|
|
/* The console must be locked */
|
|
|
|
// ASSERT(Console_locked);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Decrement the reference count. Save the new value too,
|
|
|
|
* because Console->ReferenceCount might be modified after
|
|
|
|
* the console gets unlocked but before we check whether we
|
|
|
|
* can destroy it.
|
|
|
|
*/
|
|
|
|
RefCount = _InterlockedDecrement(&Console->ReferenceCount);
|
|
|
|
|
|
|
|
/* Unlock the console if needed */
|
2018-06-10 01:23:01 +00:00
|
|
|
if (IsConsoleLocked) LeaveCriticalSection(&Console->Lock);
|
2014-05-04 00:01:48 +00:00
|
|
|
|
|
|
|
/* Delete the console if needed */
|
|
|
|
if (RefCount <= 0) ConSrvDeleteConsole(Console);
|
2013-03-30 18:44:56 +00:00
|
|
|
}
|
|
|
|
|
2013-02-10 12:36:57 +00:00
|
|
|
|
2014-05-04 00:01:48 +00:00
|
|
|
/* CONSOLE INITIALIZATION FUNCTIONS *******************************************/
|
|
|
|
|
|
|
|
VOID NTAPI
|
|
|
|
ConSrvInitConsoleSupport(VOID)
|
|
|
|
{
|
|
|
|
DPRINT("CONSRV: ConSrvInitConsoleSupport()\n");
|
|
|
|
|
|
|
|
/* Initialize the console list and its lock */
|
|
|
|
ConsoleListSize = 0;
|
|
|
|
ConsoleList = NULL;
|
2020-04-10 18:37:28 +00:00
|
|
|
// InitializeListHead(&ConDrvConsoleList);
|
2014-05-04 00:01:48 +00:00
|
|
|
RtlInitializeResource(&ListLock);
|
|
|
|
|
|
|
|
/* Should call LoadKeyboardLayout */
|
|
|
|
}
|
|
|
|
|
2014-05-03 01:59:28 +00:00
|
|
|
NTSTATUS NTAPI
|
|
|
|
ConSrvInitTerminal(IN OUT PTERMINAL Terminal,
|
2015-03-24 23:58:44 +00:00
|
|
|
IN OUT PCONSOLE_STATE_INFO ConsoleInfo,
|
|
|
|
IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
|
|
|
|
IN HANDLE ConsoleLeaderProcessHandle);
|
2014-05-03 01:59:28 +00:00
|
|
|
NTSTATUS NTAPI
|
|
|
|
ConSrvDeinitTerminal(IN OUT PTERMINAL Terminal);
|
2014-05-02 18:44:26 +00:00
|
|
|
|
2014-09-07 22:53:49 +00:00
|
|
|
|
|
|
|
static BOOL
|
2015-03-24 23:58:44 +00:00
|
|
|
LoadShellLinkConsoleInfo(IN OUT PCONSOLE_STATE_INFO ConsoleInfo,
|
2014-09-07 22:53:49 +00:00
|
|
|
IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo)
|
|
|
|
{
|
|
|
|
#define PATH_SEPARATOR L'\\'
|
|
|
|
|
|
|
|
BOOL RetVal = FALSE;
|
|
|
|
HRESULT hRes = S_OK;
|
|
|
|
SIZE_T Length = 0;
|
|
|
|
LPWSTR LinkName = NULL;
|
|
|
|
LPWSTR IconPath = NULL;
|
|
|
|
WCHAR Buffer[MAX_PATH + 1];
|
|
|
|
|
|
|
|
ConsoleInitInfo->ConsoleStartInfo->IconIndex = 0;
|
|
|
|
|
|
|
|
if ((ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
|
|
|
|
{
|
|
|
|
// return FALSE; // FIXME!! (for icon loading)
|
|
|
|
RetVal = TRUE;
|
|
|
|
goto Finish;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* 1- Find the last path separator if any */
|
|
|
|
LinkName = wcsrchr(ConsoleInfo->ConsoleTitle, PATH_SEPARATOR);
|
|
|
|
if (LinkName == NULL)
|
|
|
|
LinkName = ConsoleInfo->ConsoleTitle;
|
|
|
|
else
|
|
|
|
++LinkName; // Skip the path separator
|
|
|
|
|
|
|
|
/* 2- Check for the link extension. The name ".lnk" is considered invalid. */
|
|
|
|
Length = wcslen(LinkName);
|
2024-05-11 16:23:44 +00:00
|
|
|
if ( (Length <= 4) || (_wcsicmp(LinkName + (Length - 4), L".lnk") != 0) )
|
2014-09-07 22:53:49 +00:00
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
/* 3- It may be a link. Try to retrieve some properties */
|
|
|
|
hRes = CoInitialize(NULL);
|
|
|
|
if (SUCCEEDED(hRes))
|
|
|
|
{
|
|
|
|
/* Get a pointer to the IShellLink interface */
|
|
|
|
IShellLinkW* pshl = NULL;
|
|
|
|
hRes = CoCreateInstance(&CLSID_ShellLink,
|
2014-11-08 22:19:07 +00:00
|
|
|
NULL,
|
2014-09-07 22:53:49 +00:00
|
|
|
CLSCTX_INPROC_SERVER,
|
|
|
|
&IID_IShellLinkW,
|
|
|
|
(LPVOID*)&pshl);
|
|
|
|
if (SUCCEEDED(hRes))
|
|
|
|
{
|
|
|
|
/* Get a pointer to the IPersistFile interface */
|
|
|
|
IPersistFile* ppf = NULL;
|
|
|
|
hRes = IPersistFile_QueryInterface(pshl, &IID_IPersistFile, (LPVOID*)&ppf);
|
|
|
|
if (SUCCEEDED(hRes))
|
|
|
|
{
|
|
|
|
/* Load the shortcut */
|
|
|
|
hRes = IPersistFile_Load(ppf, ConsoleInfo->ConsoleTitle, STGM_READ);
|
|
|
|
if (SUCCEEDED(hRes))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Finally we can get the properties !
|
|
|
|
* Update the old ones if needed.
|
|
|
|
*/
|
|
|
|
INT ShowCmd = 0;
|
|
|
|
// WORD HotKey = 0;
|
|
|
|
|
|
|
|
/* Reset the name of the console with the name of the shortcut */
|
|
|
|
Length = min(/*Length*/ Length - 4, // 4 == len(".lnk")
|
2015-03-24 23:58:44 +00:00
|
|
|
(ConsoleInfo->cbSize - FIELD_OFFSET(CONSOLE_STATE_INFO, ConsoleTitle) - sizeof(UNICODE_NULL)) / sizeof(WCHAR));
|
2014-09-07 22:53:49 +00:00
|
|
|
wcsncpy(ConsoleInfo->ConsoleTitle, LinkName, Length);
|
2015-03-24 23:58:44 +00:00
|
|
|
ConsoleInfo->ConsoleTitle[Length] = UNICODE_NULL;
|
2014-09-07 22:53:49 +00:00
|
|
|
|
|
|
|
/* Get the window showing command */
|
|
|
|
hRes = IShellLinkW_GetShowCmd(pshl, &ShowCmd);
|
|
|
|
if (SUCCEEDED(hRes)) ConsoleInitInfo->ConsoleStartInfo->wShowWindow = (WORD)ShowCmd;
|
|
|
|
|
|
|
|
/* Get the hotkey */
|
|
|
|
// hRes = pshl->GetHotkey(&ShowCmd);
|
|
|
|
// if (SUCCEEDED(hRes)) ConsoleInitInfo->ConsoleStartInfo->HotKey = HotKey;
|
|
|
|
|
|
|
|
/* Get the icon location, if any */
|
|
|
|
hRes = IShellLinkW_GetIconLocation(pshl,
|
|
|
|
Buffer,
|
|
|
|
sizeof(Buffer)/sizeof(Buffer[0]) - 1, // == MAX_PATH
|
|
|
|
&ConsoleInitInfo->ConsoleStartInfo->IconIndex);
|
|
|
|
if (!SUCCEEDED(hRes))
|
|
|
|
{
|
|
|
|
ConsoleInitInfo->ConsoleStartInfo->IconIndex = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
IconPath = Buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: Since we still don't load console properties from the shortcut,
|
|
|
|
// return false. When this will be done, we will return true instead.
|
|
|
|
RetVal = TRUE; // FALSE;
|
|
|
|
}
|
|
|
|
IPersistFile_Release(ppf);
|
|
|
|
}
|
|
|
|
IShellLinkW_Release(pshl);
|
|
|
|
}
|
2023-08-18 17:06:20 +00:00
|
|
|
CoUninitialize();
|
2014-09-07 22:53:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
Finish:
|
|
|
|
|
|
|
|
if (RetVal)
|
|
|
|
{
|
|
|
|
/* Get the associated icon, if any */
|
|
|
|
if (IconPath == NULL)
|
|
|
|
{
|
|
|
|
// Question: How to retrieve the full path name
|
|
|
|
// of the app we are going to run??
|
|
|
|
Length = RtlDosSearchPath_U(ConsoleInitInfo->CurDir,
|
|
|
|
ConsoleInitInfo->AppName,
|
|
|
|
NULL,
|
|
|
|
sizeof(Buffer),
|
|
|
|
Buffer,
|
|
|
|
NULL);
|
|
|
|
if (Length > 0 && Length < sizeof(Buffer))
|
|
|
|
IconPath = Buffer;
|
|
|
|
else
|
|
|
|
IconPath = ConsoleInitInfo->AppName;
|
|
|
|
|
|
|
|
// ConsoleInitInfo->ConsoleStartInfo->IconIndex = 0;
|
|
|
|
}
|
2014-11-08 22:19:07 +00:00
|
|
|
DPRINT("IconPath = '%S' ; IconIndex = %lu\n",
|
|
|
|
IconPath, ConsoleInitInfo->ConsoleStartInfo->IconIndex);
|
2014-09-07 22:53:49 +00:00
|
|
|
if (IconPath && *IconPath)
|
|
|
|
{
|
|
|
|
HICON hIcon = NULL, hIconSm = NULL;
|
2015-03-08 14:28:19 +00:00
|
|
|
/*
|
|
|
|
* FIXME!! Because of a strange bug we have in PrivateExtractIconExW
|
|
|
|
* (see r65683 for more details), we cannot use this API to extract
|
|
|
|
* at the same time the large and small icons from the app.
|
|
|
|
* Instead we just use PrivateExtractIconsW.
|
|
|
|
*
|
2014-09-07 22:53:49 +00:00
|
|
|
PrivateExtractIconExW(IconPath,
|
|
|
|
ConsoleInitInfo->ConsoleStartInfo->IconIndex,
|
|
|
|
&hIcon,
|
|
|
|
&hIconSm,
|
|
|
|
1);
|
2015-03-08 14:28:19 +00:00
|
|
|
*/
|
|
|
|
PrivateExtractIconsW(IconPath,
|
|
|
|
ConsoleInitInfo->ConsoleStartInfo->IconIndex,
|
|
|
|
32, 32,
|
|
|
|
&hIcon, NULL, 1, LR_COPYFROMRESOURCE);
|
|
|
|
PrivateExtractIconsW(IconPath,
|
|
|
|
ConsoleInitInfo->ConsoleStartInfo->IconIndex,
|
|
|
|
16, 16,
|
|
|
|
&hIconSm, NULL, 1, LR_COPYFROMRESOURCE);
|
|
|
|
|
2014-11-08 22:19:07 +00:00
|
|
|
DPRINT("hIcon = 0x%p ; hIconSm = 0x%p\n", hIcon, hIconSm);
|
2014-09-07 22:53:49 +00:00
|
|
|
if (hIcon != NULL) ConsoleInitInfo->ConsoleStartInfo->hIcon = hIcon;
|
|
|
|
if (hIconSm != NULL) ConsoleInitInfo->ConsoleStartInfo->hIconSm = hIconSm;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// FIXME: See the previous FIXME above.
|
|
|
|
RetVal = FALSE;
|
|
|
|
|
|
|
|
return RetVal;
|
|
|
|
}
|
|
|
|
|
2013-10-12 15:44:22 +00:00
|
|
|
NTSTATUS NTAPI
|
2013-07-06 19:47:53 +00:00
|
|
|
ConSrvInitConsole(OUT PHANDLE NewConsoleHandle,
|
2014-08-12 14:59:13 +00:00
|
|
|
OUT PCONSRV_CONSOLE* NewConsole,
|
2014-09-07 22:53:49 +00:00
|
|
|
IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo,
|
2015-03-11 01:21:29 +00:00
|
|
|
IN PCSR_PROCESS ConsoleLeaderProcess)
|
2010-05-31 06:28:55 +00:00
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
2013-07-06 19:47:53 +00:00
|
|
|
HANDLE ConsoleHandle;
|
2014-08-12 14:59:13 +00:00
|
|
|
PCONSRV_CONSOLE Console;
|
2015-03-24 23:58:44 +00:00
|
|
|
|
|
|
|
BYTE ConsoleInfoBuffer[sizeof(CONSOLE_STATE_INFO) + MAX_PATH * sizeof(WCHAR)]; // CONSRV console information
|
|
|
|
PCONSOLE_STATE_INFO ConsoleInfo = (PCONSOLE_STATE_INFO)&ConsoleInfoBuffer;
|
|
|
|
CONSOLE_INFO DrvConsoleInfo; // Console information for CONDRV
|
|
|
|
|
2013-06-23 00:18:47 +00:00
|
|
|
SIZE_T Length = 0;
|
2014-05-02 18:44:26 +00:00
|
|
|
|
2014-05-03 01:59:28 +00:00
|
|
|
TERMINAL Terminal; /* The ConSrv terminal for this console */
|
2010-05-31 06:28:55 +00:00
|
|
|
|
2014-09-07 22:53:49 +00:00
|
|
|
if (NewConsole == NULL || ConsoleInitInfo == NULL)
|
2013-06-23 00:18:47 +00:00
|
|
|
return STATUS_INVALID_PARAMETER;
|
2013-01-02 00:32:20 +00:00
|
|
|
|
2013-06-23 00:18:47 +00:00
|
|
|
*NewConsole = NULL;
|
2013-01-02 00:32:20 +00:00
|
|
|
|
2020-04-13 21:24:55 +00:00
|
|
|
DPRINT("Initialization of console '%S' for process '%S' on desktop '%S'\n",
|
|
|
|
ConsoleInitInfo->ConsoleTitle ? ConsoleInitInfo->ConsoleTitle : L"n/a",
|
|
|
|
ConsoleInitInfo->AppName ? ConsoleInitInfo->AppName : L"n/a",
|
|
|
|
ConsoleInitInfo->Desktop ? ConsoleInitInfo->Desktop : L"n/a");
|
|
|
|
|
2013-02-10 12:36:57 +00:00
|
|
|
/*
|
[CONSOLE.DLL-KERNEL32-CONSRV]
Fix the console properties dialog, when launching and transmitting console properties. Before, the properties dialog was directly launched by the console server (consrv), running with CSRSS (System) privileges, what constituted a security hole. Now, I create a remote thread in the running process owning the console for launching the properties dialog (thus it has only user privileges, and not System ones anymore). For that purpose, I basically took the technique described in the following paper (Cesar Cerrudo, "Story of a dumb patch", http://www.argeniss.com/research/MSBugPaper.pdf or http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf), where basically the console server shares the console properties via a shared memory section with the console properties dialog dll. The address of the thread which launches the dialog in the context of the console app is given to the console server the same way as we do for the control handler (called e.g. when you press Ctrl-C, etc...)
Of course this is quite hackish, because you have the GUI interface split between the console server and the console properties dialog dll. Something far more elegant would be to put all the GUI thingie into a dedicated dll or exe, running with the same privileges as the console program itself (a kind of console -- or terminal -- emulator).
[CONSOLE.DLL]
Fix retriving / setting colors.c and other things.
[CONSRV.DLL]
- Fix retrieving / setting console properties from the registry (via the HKCU\Console\* keys), via the shell shortcuts (not totally done at the moment, because somebody has to implement properly that thing : http://msdn.microsoft.com/en-us/library/windows/desktop/bb773359(v=vs.85).aspx (NT_CONSOLE_PROPS structure stored as a shortcut data block) (at application launching time), and via the console properties dialog.
- Few DPRINTs removed.
svn path=/branches/ros-csrss/; revision=58415
2013-03-03 15:35:12 +00:00
|
|
|
* Load the console settings
|
|
|
|
*/
|
2015-03-24 23:58:44 +00:00
|
|
|
RtlZeroMemory(ConsoleInfo, sizeof(ConsoleInfoBuffer));
|
|
|
|
ConsoleInfo->cbSize = sizeof(ConsoleInfoBuffer);
|
[CONSOLE.DLL-KERNEL32-CONSRV]
Fix the console properties dialog, when launching and transmitting console properties. Before, the properties dialog was directly launched by the console server (consrv), running with CSRSS (System) privileges, what constituted a security hole. Now, I create a remote thread in the running process owning the console for launching the properties dialog (thus it has only user privileges, and not System ones anymore). For that purpose, I basically took the technique described in the following paper (Cesar Cerrudo, "Story of a dumb patch", http://www.argeniss.com/research/MSBugPaper.pdf or http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf), where basically the console server shares the console properties via a shared memory section with the console properties dialog dll. The address of the thread which launches the dialog in the context of the console app is given to the console server the same way as we do for the control handler (called e.g. when you press Ctrl-C, etc...)
Of course this is quite hackish, because you have the GUI interface split between the console server and the console properties dialog dll. Something far more elegant would be to put all the GUI thingie into a dedicated dll or exe, running with the same privileges as the console program itself (a kind of console -- or terminal -- emulator).
[CONSOLE.DLL]
Fix retriving / setting colors.c and other things.
[CONSRV.DLL]
- Fix retrieving / setting console properties from the registry (via the HKCU\Console\* keys), via the shell shortcuts (not totally done at the moment, because somebody has to implement properly that thing : http://msdn.microsoft.com/en-us/library/windows/desktop/bb773359(v=vs.85).aspx (NT_CONSOLE_PROPS structure stored as a shortcut data block) (at application launching time), and via the console properties dialog.
- Few DPRINTs removed.
svn path=/branches/ros-csrss/; revision=58415
2013-03-03 15:35:12 +00:00
|
|
|
|
2015-04-05 23:04:42 +00:00
|
|
|
/* 1. Get the title of the console (initialize ConsoleInfo->ConsoleTitle) */
|
2014-09-07 22:53:49 +00:00
|
|
|
Length = min(ConsoleInitInfo->TitleLength,
|
2015-03-24 23:58:44 +00:00
|
|
|
(ConsoleInfo->cbSize - FIELD_OFFSET(CONSOLE_STATE_INFO, ConsoleTitle) - sizeof(UNICODE_NULL)) / sizeof(WCHAR));
|
|
|
|
wcsncpy(ConsoleInfo->ConsoleTitle, ConsoleInitInfo->ConsoleTitle, Length);
|
|
|
|
ConsoleInfo->ConsoleTitle[Length] = UNICODE_NULL; // NULL-terminate it.
|
2013-06-23 00:18:47 +00:00
|
|
|
|
2015-04-05 23:04:42 +00:00
|
|
|
/* 2. Impersonate the caller in order to retrieve settings in its context */
|
|
|
|
if (!CsrImpersonateClient(NULL))
|
|
|
|
return STATUS_BAD_IMPERSONATION_LEVEL;
|
|
|
|
|
|
|
|
/* 3. Load the default settings */
|
|
|
|
ConCfgGetDefaultSettings(ConsoleInfo);
|
|
|
|
|
2014-09-07 22:53:49 +00:00
|
|
|
/*
|
2015-04-05 23:04:42 +00:00
|
|
|
* 4. Load per-application terminal settings.
|
2014-09-07 22:53:49 +00:00
|
|
|
*
|
|
|
|
* Check whether the process creating the console was launched via
|
|
|
|
* a shell-link. ConsoleInfo->ConsoleTitle may be updated with the
|
|
|
|
* name of the shortcut, and ConsoleStartInfo->Icon[Path|Index] too.
|
|
|
|
*/
|
|
|
|
// if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) // FIXME!! (for icon loading)
|
|
|
|
{
|
2015-03-24 23:58:44 +00:00
|
|
|
if (!LoadShellLinkConsoleInfo(ConsoleInfo, ConsoleInitInfo))
|
2014-09-07 22:53:49 +00:00
|
|
|
{
|
|
|
|
ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags &= ~STARTF_TITLEISLINKNAME;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
[CONSOLE.DLL-KERNEL32-CONSRV]
Fix the console properties dialog, when launching and transmitting console properties. Before, the properties dialog was directly launched by the console server (consrv), running with CSRSS (System) privileges, what constituted a security hole. Now, I create a remote thread in the running process owning the console for launching the properties dialog (thus it has only user privileges, and not System ones anymore). For that purpose, I basically took the technique described in the following paper (Cesar Cerrudo, "Story of a dumb patch", http://www.argeniss.com/research/MSBugPaper.pdf or http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf), where basically the console server shares the console properties via a shared memory section with the console properties dialog dll. The address of the thread which launches the dialog in the context of the console app is given to the console server the same way as we do for the control handler (called e.g. when you press Ctrl-C, etc...)
Of course this is quite hackish, because you have the GUI interface split between the console server and the console properties dialog dll. Something far more elegant would be to put all the GUI thingie into a dedicated dll or exe, running with the same privileges as the console program itself (a kind of console -- or terminal -- emulator).
[CONSOLE.DLL]
Fix retriving / setting colors.c and other things.
[CONSRV.DLL]
- Fix retrieving / setting console properties from the registry (via the HKCU\Console\* keys), via the shell shortcuts (not totally done at the moment, because somebody has to implement properly that thing : http://msdn.microsoft.com/en-us/library/windows/desktop/bb773359(v=vs.85).aspx (NT_CONSOLE_PROPS structure stored as a shortcut data block) (at application launching time), and via the console properties dialog.
- Few DPRINTs removed.
svn path=/branches/ros-csrss/; revision=58415
2013-03-03 15:35:12 +00:00
|
|
|
/*
|
2015-04-05 23:04:42 +00:00
|
|
|
* 5. Load the remaining console settings via the registry.
|
[CONSOLE.DLL-KERNEL32-CONSRV]
Fix the console properties dialog, when launching and transmitting console properties. Before, the properties dialog was directly launched by the console server (consrv), running with CSRSS (System) privileges, what constituted a security hole. Now, I create a remote thread in the running process owning the console for launching the properties dialog (thus it has only user privileges, and not System ones anymore). For that purpose, I basically took the technique described in the following paper (Cesar Cerrudo, "Story of a dumb patch", http://www.argeniss.com/research/MSBugPaper.pdf or http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf), where basically the console server shares the console properties via a shared memory section with the console properties dialog dll. The address of the thread which launches the dialog in the context of the console app is given to the console server the same way as we do for the control handler (called e.g. when you press Ctrl-C, etc...)
Of course this is quite hackish, because you have the GUI interface split between the console server and the console properties dialog dll. Something far more elegant would be to put all the GUI thingie into a dedicated dll or exe, running with the same privileges as the console program itself (a kind of console -- or terminal -- emulator).
[CONSOLE.DLL]
Fix retriving / setting colors.c and other things.
[CONSRV.DLL]
- Fix retrieving / setting console properties from the registry (via the HKCU\Console\* keys), via the shell shortcuts (not totally done at the moment, because somebody has to implement properly that thing : http://msdn.microsoft.com/en-us/library/windows/desktop/bb773359(v=vs.85).aspx (NT_CONSOLE_PROPS structure stored as a shortcut data block) (at application launching time), and via the console properties dialog.
- Few DPRINTs removed.
svn path=/branches/ros-csrss/; revision=58415
2013-03-03 15:35:12 +00:00
|
|
|
*/
|
2014-09-07 22:53:49 +00:00
|
|
|
if ((ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_TITLEISLINKNAME) == 0)
|
[CONSOLE.DLL-KERNEL32-CONSRV]
Fix the console properties dialog, when launching and transmitting console properties. Before, the properties dialog was directly launched by the console server (consrv), running with CSRSS (System) privileges, what constituted a security hole. Now, I create a remote thread in the running process owning the console for launching the properties dialog (thus it has only user privileges, and not System ones anymore). For that purpose, I basically took the technique described in the following paper (Cesar Cerrudo, "Story of a dumb patch", http://www.argeniss.com/research/MSBugPaper.pdf or http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf), where basically the console server shares the console properties via a shared memory section with the console properties dialog dll. The address of the thread which launches the dialog in the context of the console app is given to the console server the same way as we do for the control handler (called e.g. when you press Ctrl-C, etc...)
Of course this is quite hackish, because you have the GUI interface split between the console server and the console properties dialog dll. Something far more elegant would be to put all the GUI thingie into a dedicated dll or exe, running with the same privileges as the console program itself (a kind of console -- or terminal -- emulator).
[CONSOLE.DLL]
Fix retriving / setting colors.c and other things.
[CONSRV.DLL]
- Fix retrieving / setting console properties from the registry (via the HKCU\Console\* keys), via the shell shortcuts (not totally done at the moment, because somebody has to implement properly that thing : http://msdn.microsoft.com/en-us/library/windows/desktop/bb773359(v=vs.85).aspx (NT_CONSOLE_PROPS structure stored as a shortcut data block) (at application launching time), and via the console properties dialog.
- Few DPRINTs removed.
svn path=/branches/ros-csrss/; revision=58415
2013-03-03 15:35:12 +00:00
|
|
|
{
|
|
|
|
/*
|
|
|
|
* Either we weren't created by an app launched via a shell-link,
|
|
|
|
* or we failed to load shell-link console properties.
|
|
|
|
* Therefore, load the console infos for the application from the registry.
|
|
|
|
*/
|
2015-04-05 23:04:42 +00:00
|
|
|
ConCfgReadUserSettings(ConsoleInfo, FALSE);
|
[CONSOLE.DLL-KERNEL32-CONSRV]
Fix the console properties dialog, when launching and transmitting console properties. Before, the properties dialog was directly launched by the console server (consrv), running with CSRSS (System) privileges, what constituted a security hole. Now, I create a remote thread in the running process owning the console for launching the properties dialog (thus it has only user privileges, and not System ones anymore). For that purpose, I basically took the technique described in the following paper (Cesar Cerrudo, "Story of a dumb patch", http://www.argeniss.com/research/MSBugPaper.pdf or http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf), where basically the console server shares the console properties via a shared memory section with the console properties dialog dll. The address of the thread which launches the dialog in the context of the console app is given to the console server the same way as we do for the control handler (called e.g. when you press Ctrl-C, etc...)
Of course this is quite hackish, because you have the GUI interface split between the console server and the console properties dialog dll. Something far more elegant would be to put all the GUI thingie into a dedicated dll or exe, running with the same privileges as the console program itself (a kind of console -- or terminal -- emulator).
[CONSOLE.DLL]
Fix retriving / setting colors.c and other things.
[CONSRV.DLL]
- Fix retrieving / setting console properties from the registry (via the HKCU\Console\* keys), via the shell shortcuts (not totally done at the moment, because somebody has to implement properly that thing : http://msdn.microsoft.com/en-us/library/windows/desktop/bb773359(v=vs.85).aspx (NT_CONSOLE_PROPS structure stored as a shortcut data block) (at application launching time), and via the console properties dialog.
- Few DPRINTs removed.
svn path=/branches/ros-csrss/; revision=58415
2013-03-03 15:35:12 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Now, update them with the properties the user might gave to us
|
|
|
|
* via the STARTUPINFO structure before calling CreateProcess
|
|
|
|
* (and which was transmitted via the ConsoleStartInfo structure).
|
2013-03-24 17:08:10 +00:00
|
|
|
* We therefore overwrite the values read in the registry.
|
[CONSOLE.DLL-KERNEL32-CONSRV]
Fix the console properties dialog, when launching and transmitting console properties. Before, the properties dialog was directly launched by the console server (consrv), running with CSRSS (System) privileges, what constituted a security hole. Now, I create a remote thread in the running process owning the console for launching the properties dialog (thus it has only user privileges, and not System ones anymore). For that purpose, I basically took the technique described in the following paper (Cesar Cerrudo, "Story of a dumb patch", http://www.argeniss.com/research/MSBugPaper.pdf or http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf), where basically the console server shares the console properties via a shared memory section with the console properties dialog dll. The address of the thread which launches the dialog in the context of the console app is given to the console server the same way as we do for the control handler (called e.g. when you press Ctrl-C, etc...)
Of course this is quite hackish, because you have the GUI interface split between the console server and the console properties dialog dll. Something far more elegant would be to put all the GUI thingie into a dedicated dll or exe, running with the same privileges as the console program itself (a kind of console -- or terminal -- emulator).
[CONSOLE.DLL]
Fix retriving / setting colors.c and other things.
[CONSRV.DLL]
- Fix retrieving / setting console properties from the registry (via the HKCU\Console\* keys), via the shell shortcuts (not totally done at the moment, because somebody has to implement properly that thing : http://msdn.microsoft.com/en-us/library/windows/desktop/bb773359(v=vs.85).aspx (NT_CONSOLE_PROPS structure stored as a shortcut data block) (at application launching time), and via the console properties dialog.
- Few DPRINTs removed.
svn path=/branches/ros-csrss/; revision=58415
2013-03-03 15:35:12 +00:00
|
|
|
*/
|
2014-09-07 22:53:49 +00:00
|
|
|
if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USEFILLATTRIBUTE)
|
[CONSOLE.DLL-KERNEL32-CONSRV]
Fix the console properties dialog, when launching and transmitting console properties. Before, the properties dialog was directly launched by the console server (consrv), running with CSRSS (System) privileges, what constituted a security hole. Now, I create a remote thread in the running process owning the console for launching the properties dialog (thus it has only user privileges, and not System ones anymore). For that purpose, I basically took the technique described in the following paper (Cesar Cerrudo, "Story of a dumb patch", http://www.argeniss.com/research/MSBugPaper.pdf or http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf), where basically the console server shares the console properties via a shared memory section with the console properties dialog dll. The address of the thread which launches the dialog in the context of the console app is given to the console server the same way as we do for the control handler (called e.g. when you press Ctrl-C, etc...)
Of course this is quite hackish, because you have the GUI interface split between the console server and the console properties dialog dll. Something far more elegant would be to put all the GUI thingie into a dedicated dll or exe, running with the same privileges as the console program itself (a kind of console -- or terminal -- emulator).
[CONSOLE.DLL]
Fix retriving / setting colors.c and other things.
[CONSRV.DLL]
- Fix retrieving / setting console properties from the registry (via the HKCU\Console\* keys), via the shell shortcuts (not totally done at the moment, because somebody has to implement properly that thing : http://msdn.microsoft.com/en-us/library/windows/desktop/bb773359(v=vs.85).aspx (NT_CONSOLE_PROPS structure stored as a shortcut data block) (at application launching time), and via the console properties dialog.
- Few DPRINTs removed.
svn path=/branches/ros-csrss/; revision=58415
2013-03-03 15:35:12 +00:00
|
|
|
{
|
2015-03-24 23:58:44 +00:00
|
|
|
ConsoleInfo->ScreenAttributes = (USHORT)ConsoleInitInfo->ConsoleStartInfo->wFillAttribute;
|
[CONSOLE.DLL-KERNEL32-CONSRV]
Fix the console properties dialog, when launching and transmitting console properties. Before, the properties dialog was directly launched by the console server (consrv), running with CSRSS (System) privileges, what constituted a security hole. Now, I create a remote thread in the running process owning the console for launching the properties dialog (thus it has only user privileges, and not System ones anymore). For that purpose, I basically took the technique described in the following paper (Cesar Cerrudo, "Story of a dumb patch", http://www.argeniss.com/research/MSBugPaper.pdf or http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf), where basically the console server shares the console properties via a shared memory section with the console properties dialog dll. The address of the thread which launches the dialog in the context of the console app is given to the console server the same way as we do for the control handler (called e.g. when you press Ctrl-C, etc...)
Of course this is quite hackish, because you have the GUI interface split between the console server and the console properties dialog dll. Something far more elegant would be to put all the GUI thingie into a dedicated dll or exe, running with the same privileges as the console program itself (a kind of console -- or terminal -- emulator).
[CONSOLE.DLL]
Fix retriving / setting colors.c and other things.
[CONSRV.DLL]
- Fix retrieving / setting console properties from the registry (via the HKCU\Console\* keys), via the shell shortcuts (not totally done at the moment, because somebody has to implement properly that thing : http://msdn.microsoft.com/en-us/library/windows/desktop/bb773359(v=vs.85).aspx (NT_CONSOLE_PROPS structure stored as a shortcut data block) (at application launching time), and via the console properties dialog.
- Few DPRINTs removed.
svn path=/branches/ros-csrss/; revision=58415
2013-03-03 15:35:12 +00:00
|
|
|
}
|
2014-09-07 22:53:49 +00:00
|
|
|
if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USECOUNTCHARS)
|
[CONSOLE.DLL-KERNEL32-CONSRV]
Fix the console properties dialog, when launching and transmitting console properties. Before, the properties dialog was directly launched by the console server (consrv), running with CSRSS (System) privileges, what constituted a security hole. Now, I create a remote thread in the running process owning the console for launching the properties dialog (thus it has only user privileges, and not System ones anymore). For that purpose, I basically took the technique described in the following paper (Cesar Cerrudo, "Story of a dumb patch", http://www.argeniss.com/research/MSBugPaper.pdf or http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf), where basically the console server shares the console properties via a shared memory section with the console properties dialog dll. The address of the thread which launches the dialog in the context of the console app is given to the console server the same way as we do for the control handler (called e.g. when you press Ctrl-C, etc...)
Of course this is quite hackish, because you have the GUI interface split between the console server and the console properties dialog dll. Something far more elegant would be to put all the GUI thingie into a dedicated dll or exe, running with the same privileges as the console program itself (a kind of console -- or terminal -- emulator).
[CONSOLE.DLL]
Fix retriving / setting colors.c and other things.
[CONSRV.DLL]
- Fix retrieving / setting console properties from the registry (via the HKCU\Console\* keys), via the shell shortcuts (not totally done at the moment, because somebody has to implement properly that thing : http://msdn.microsoft.com/en-us/library/windows/desktop/bb773359(v=vs.85).aspx (NT_CONSOLE_PROPS structure stored as a shortcut data block) (at application launching time), and via the console properties dialog.
- Few DPRINTs removed.
svn path=/branches/ros-csrss/; revision=58415
2013-03-03 15:35:12 +00:00
|
|
|
{
|
2015-03-24 23:58:44 +00:00
|
|
|
ConsoleInfo->ScreenBufferSize = ConsoleInitInfo->ConsoleStartInfo->dwScreenBufferSize;
|
[CONSOLE.DLL-KERNEL32-CONSRV]
Fix the console properties dialog, when launching and transmitting console properties. Before, the properties dialog was directly launched by the console server (consrv), running with CSRSS (System) privileges, what constituted a security hole. Now, I create a remote thread in the running process owning the console for launching the properties dialog (thus it has only user privileges, and not System ones anymore). For that purpose, I basically took the technique described in the following paper (Cesar Cerrudo, "Story of a dumb patch", http://www.argeniss.com/research/MSBugPaper.pdf or http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf), where basically the console server shares the console properties via a shared memory section with the console properties dialog dll. The address of the thread which launches the dialog in the context of the console app is given to the console server the same way as we do for the control handler (called e.g. when you press Ctrl-C, etc...)
Of course this is quite hackish, because you have the GUI interface split between the console server and the console properties dialog dll. Something far more elegant would be to put all the GUI thingie into a dedicated dll or exe, running with the same privileges as the console program itself (a kind of console -- or terminal -- emulator).
[CONSOLE.DLL]
Fix retriving / setting colors.c and other things.
[CONSRV.DLL]
- Fix retrieving / setting console properties from the registry (via the HKCU\Console\* keys), via the shell shortcuts (not totally done at the moment, because somebody has to implement properly that thing : http://msdn.microsoft.com/en-us/library/windows/desktop/bb773359(v=vs.85).aspx (NT_CONSOLE_PROPS structure stored as a shortcut data block) (at application launching time), and via the console properties dialog.
- Few DPRINTs removed.
svn path=/branches/ros-csrss/; revision=58415
2013-03-03 15:35:12 +00:00
|
|
|
}
|
2014-09-07 22:53:49 +00:00
|
|
|
if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USESIZE)
|
[CONSOLE.DLL-KERNEL32-CONSRV]
Fix the console properties dialog, when launching and transmitting console properties. Before, the properties dialog was directly launched by the console server (consrv), running with CSRSS (System) privileges, what constituted a security hole. Now, I create a remote thread in the running process owning the console for launching the properties dialog (thus it has only user privileges, and not System ones anymore). For that purpose, I basically took the technique described in the following paper (Cesar Cerrudo, "Story of a dumb patch", http://www.argeniss.com/research/MSBugPaper.pdf or http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf), where basically the console server shares the console properties via a shared memory section with the console properties dialog dll. The address of the thread which launches the dialog in the context of the console app is given to the console server the same way as we do for the control handler (called e.g. when you press Ctrl-C, etc...)
Of course this is quite hackish, because you have the GUI interface split between the console server and the console properties dialog dll. Something far more elegant would be to put all the GUI thingie into a dedicated dll or exe, running with the same privileges as the console program itself (a kind of console -- or terminal -- emulator).
[CONSOLE.DLL]
Fix retriving / setting colors.c and other things.
[CONSRV.DLL]
- Fix retrieving / setting console properties from the registry (via the HKCU\Console\* keys), via the shell shortcuts (not totally done at the moment, because somebody has to implement properly that thing : http://msdn.microsoft.com/en-us/library/windows/desktop/bb773359(v=vs.85).aspx (NT_CONSOLE_PROPS structure stored as a shortcut data block) (at application launching time), and via the console properties dialog.
- Few DPRINTs removed.
svn path=/branches/ros-csrss/; revision=58415
2013-03-03 15:35:12 +00:00
|
|
|
{
|
2015-03-24 23:58:44 +00:00
|
|
|
ConsoleInfo->WindowSize = ConsoleInitInfo->ConsoleStartInfo->dwWindowSize;
|
[CONSOLE.DLL-KERNEL32-CONSRV]
Fix the console properties dialog, when launching and transmitting console properties. Before, the properties dialog was directly launched by the console server (consrv), running with CSRSS (System) privileges, what constituted a security hole. Now, I create a remote thread in the running process owning the console for launching the properties dialog (thus it has only user privileges, and not System ones anymore). For that purpose, I basically took the technique described in the following paper (Cesar Cerrudo, "Story of a dumb patch", http://www.argeniss.com/research/MSBugPaper.pdf or http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf), where basically the console server shares the console properties via a shared memory section with the console properties dialog dll. The address of the thread which launches the dialog in the context of the console app is given to the console server the same way as we do for the control handler (called e.g. when you press Ctrl-C, etc...)
Of course this is quite hackish, because you have the GUI interface split between the console server and the console properties dialog dll. Something far more elegant would be to put all the GUI thingie into a dedicated dll or exe, running with the same privileges as the console program itself (a kind of console -- or terminal -- emulator).
[CONSOLE.DLL]
Fix retriving / setting colors.c and other things.
[CONSRV.DLL]
- Fix retrieving / setting console properties from the registry (via the HKCU\Console\* keys), via the shell shortcuts (not totally done at the moment, because somebody has to implement properly that thing : http://msdn.microsoft.com/en-us/library/windows/desktop/bb773359(v=vs.85).aspx (NT_CONSOLE_PROPS structure stored as a shortcut data block) (at application launching time), and via the console properties dialog.
- Few DPRINTs removed.
svn path=/branches/ros-csrss/; revision=58415
2013-03-03 15:35:12 +00:00
|
|
|
}
|
2015-03-24 23:58:44 +00:00
|
|
|
|
|
|
|
#if 0
|
|
|
|
/*
|
|
|
|
* Now, update them with the properties the user might gave to us
|
|
|
|
* via the STARTUPINFO structure before calling CreateProcess
|
|
|
|
* (and which was transmitted via the ConsoleStartInfo structure).
|
|
|
|
* We therefore overwrite the values read in the registry.
|
|
|
|
*/
|
|
|
|
if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_USEPOSITION)
|
|
|
|
{
|
|
|
|
ConsoleInfo->AutoPosition = FALSE;
|
|
|
|
ConsoleInfo->WindowPosition.x = ConsoleInitInfo->ConsoleStartInfo->dwWindowOrigin.X;
|
|
|
|
ConsoleInfo->WindowPosition.y = ConsoleInitInfo->ConsoleStartInfo->dwWindowOrigin.Y;
|
|
|
|
}
|
|
|
|
if (ConsoleInitInfo->ConsoleStartInfo->dwStartupFlags & STARTF_RUNFULLSCREEN)
|
|
|
|
{
|
|
|
|
ConsoleInfo->FullScreen = TRUE;
|
|
|
|
}
|
|
|
|
#endif
|
2011-04-09 12:01:36 +00:00
|
|
|
}
|
2010-05-31 06:28:55 +00:00
|
|
|
|
2015-04-05 23:04:42 +00:00
|
|
|
/* 6. Revert impersonation */
|
2015-03-24 23:58:44 +00:00
|
|
|
CsrRevertToSelf();
|
|
|
|
|
2013-06-23 00:18:47 +00:00
|
|
|
/* Set-up the code page */
|
2015-03-24 23:58:44 +00:00
|
|
|
ConsoleInfo->CodePage = GetOEMCP();
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize the ConSrv terminal and give it a chance to load
|
|
|
|
* its own settings and override the console settings.
|
|
|
|
*/
|
|
|
|
Status = ConSrvInitTerminal(&Terminal,
|
|
|
|
ConsoleInfo,
|
|
|
|
ConsoleInitInfo,
|
|
|
|
ConsoleLeaderProcess->ProcessHandle);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("CONSRV: Failed to initialize a terminal, Status = 0x%08lx\n", Status);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
DPRINT("CONSRV: Terminal initialized\n");
|
2010-05-31 06:28:55 +00:00
|
|
|
|
2014-05-02 18:44:26 +00:00
|
|
|
/* Initialize a new console via the driver */
|
2015-03-24 23:58:44 +00:00
|
|
|
// DrvConsoleInfo.InputBufferSize = 0;
|
|
|
|
DrvConsoleInfo.ScreenBufferSize = ConsoleInfo->ScreenBufferSize;
|
|
|
|
DrvConsoleInfo.ConsoleSize = ConsoleInfo->WindowSize;
|
|
|
|
DrvConsoleInfo.CursorSize = ConsoleInfo->CursorSize;
|
|
|
|
// DrvConsoleInfo.CursorBlinkOn = ConsoleInfo->CursorBlinkOn;
|
|
|
|
DrvConsoleInfo.ScreenAttrib = ConsoleInfo->ScreenAttributes;
|
|
|
|
DrvConsoleInfo.PopupAttrib = ConsoleInfo->PopupAttributes;
|
|
|
|
DrvConsoleInfo.CodePage = ConsoleInfo->CodePage;
|
2020-04-10 18:37:28 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Allocate a new console
|
|
|
|
*/
|
|
|
|
Console = ConsoleAllocHeap(HEAP_ZERO_MEMORY, sizeof(*Console));
|
|
|
|
if (Console == NULL)
|
|
|
|
{
|
|
|
|
DPRINT1("Not enough memory for console creation.\n");
|
|
|
|
ConSrvDeinitTerminal(&Terminal);
|
|
|
|
return STATUS_NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = ConDrvInitConsole((PCONSOLE)Console, &DrvConsoleInfo);
|
2013-02-10 12:36:57 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2013-06-23 00:18:47 +00:00
|
|
|
DPRINT1("Creating a new console failed, Status = 0x%08lx\n", Status);
|
2020-04-10 18:37:28 +00:00
|
|
|
ConsoleFreeHeap(Console);
|
2014-05-03 01:59:28 +00:00
|
|
|
ConSrvDeinitTerminal(&Terminal);
|
2013-02-10 12:36:57 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2013-06-23 00:18:47 +00:00
|
|
|
DPRINT("Console initialized\n");
|
2012-11-24 12:40:56 +00:00
|
|
|
|
2014-05-02 16:46:13 +00:00
|
|
|
/*** Register ConSrv features ***/
|
2014-05-02 18:44:26 +00:00
|
|
|
|
2014-09-07 22:53:49 +00:00
|
|
|
/* Initialize the console title */
|
|
|
|
#if 0
|
|
|
|
WCHAR DefaultTitle[128];
|
|
|
|
#endif
|
2015-03-24 23:58:44 +00:00
|
|
|
ConsoleCreateUnicodeString(&Console->OriginalTitle, ConsoleInfo->ConsoleTitle);
|
2014-09-07 22:53:49 +00:00
|
|
|
#if 0
|
2015-03-24 23:58:44 +00:00
|
|
|
if (ConsoleInfo->ConsoleTitle[0] == UNICODE_NULL)
|
2014-09-07 22:53:49 +00:00
|
|
|
{
|
|
|
|
if (LoadStringW(ConSrvDllInstance, IDS_CONSOLE_TITLE, DefaultTitle, sizeof(DefaultTitle) / sizeof(DefaultTitle[0])))
|
|
|
|
{
|
|
|
|
ConsoleCreateUnicodeString(&Console->Title, DefaultTitle);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ConsoleCreateUnicodeString(&Console->Title, L"ReactOS Console");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
#endif
|
2015-03-24 23:58:44 +00:00
|
|
|
ConsoleCreateUnicodeString(&Console->Title, ConsoleInfo->ConsoleTitle);
|
2014-09-07 22:53:49 +00:00
|
|
|
#if 0
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2014-05-02 18:44:26 +00:00
|
|
|
/* Initialize process support */
|
2020-04-10 18:37:28 +00:00
|
|
|
// InitProcessSupport(Console);
|
2014-05-02 16:46:13 +00:00
|
|
|
InitializeListHead(&Console->ProcessList);
|
|
|
|
Console->NotifiedLastCloseProcess = NULL;
|
|
|
|
Console->NotifyLastClose = FALSE;
|
2015-08-15 17:05:13 +00:00
|
|
|
Console->HasFocus = FALSE;
|
2014-05-02 18:44:26 +00:00
|
|
|
|
|
|
|
/* Initialize pausing support */
|
|
|
|
Console->PauseFlags = 0;
|
2014-05-02 16:46:13 +00:00
|
|
|
InitializeListHead(&Console->ReadWaitQueue);
|
|
|
|
InitializeListHead(&Console->WriteWaitQueue);
|
|
|
|
|
2014-05-04 00:01:48 +00:00
|
|
|
/* Initialize the alias and history buffers */
|
2020-04-10 18:37:28 +00:00
|
|
|
// InitAliasesHistory(Console);
|
2014-05-04 00:01:48 +00:00
|
|
|
Console->Aliases = NULL;
|
|
|
|
InitializeListHead(&Console->HistoryBuffers);
|
2020-02-29 16:35:57 +00:00
|
|
|
Console->NumberOfHistoryBuffers = 0;
|
|
|
|
Console->MaxNumberOfHistoryBuffers = ConsoleInfo->NumberOfHistoryBuffers;
|
|
|
|
Console->HistoryBufferSize = ConsoleInfo->HistoryBufferSize;
|
|
|
|
Console->HistoryNoDup = ConsoleInfo->HistoryNoDup;
|
2014-05-04 00:01:48 +00:00
|
|
|
|
2014-08-29 19:45:45 +00:00
|
|
|
/* Initialize the Input Line Discipline */
|
2020-04-10 18:37:28 +00:00
|
|
|
// InitLineInput(Console);
|
2014-08-29 19:45:45 +00:00
|
|
|
Console->LineBuffer = NULL;
|
|
|
|
Console->LinePos = Console->LineMaxSize = Console->LineSize = 0;
|
|
|
|
Console->LineComplete = Console->LineUpPressed = FALSE;
|
|
|
|
// LineWakeupMask
|
|
|
|
Console->LineInsertToggle =
|
2015-03-24 23:58:44 +00:00
|
|
|
Console->InsertMode = ConsoleInfo->InsertMode;
|
|
|
|
Console->QuickEdit = ConsoleInfo->QuickEdit;
|
2014-05-02 18:44:26 +00:00
|
|
|
|
2014-08-30 16:20:32 +00:00
|
|
|
/* Popup windows */
|
|
|
|
InitializeListHead(&Console->PopupWindows);
|
|
|
|
|
2014-08-11 20:28:40 +00:00
|
|
|
/* Colour table */
|
2015-03-24 23:58:44 +00:00
|
|
|
RtlCopyMemory(Console->Colors, ConsoleInfo->ColorTable,
|
|
|
|
sizeof(ConsoleInfo->ColorTable));
|
2014-08-11 20:28:40 +00:00
|
|
|
|
2014-11-22 22:13:08 +00:00
|
|
|
/* Create the Initialization Events */
|
|
|
|
Status = NtCreateEvent(&Console->InitEvents[INIT_SUCCESS], EVENT_ALL_ACCESS,
|
|
|
|
NULL, NotificationEvent, FALSE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("NtCreateEvent(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status);
|
2020-04-10 18:37:28 +00:00
|
|
|
ConDrvDeleteConsole((PCONSOLE)Console);
|
2014-11-22 22:13:08 +00:00
|
|
|
ConSrvDeinitTerminal(&Terminal);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
Status = NtCreateEvent(&Console->InitEvents[INIT_FAILURE], EVENT_ALL_ACCESS,
|
|
|
|
NULL, NotificationEvent, FALSE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("NtCreateEvent(InitEvents[INIT_FAILURE]) failed: %lu\n", Status);
|
|
|
|
NtClose(Console->InitEvents[INIT_SUCCESS]);
|
2020-04-10 18:37:28 +00:00
|
|
|
ConDrvDeleteConsole((PCONSOLE)Console);
|
2014-11-22 22:13:08 +00:00
|
|
|
ConSrvDeinitTerminal(&Terminal);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2014-09-05 21:12:42 +00:00
|
|
|
/*
|
|
|
|
* Attach the ConSrv terminal to the console.
|
|
|
|
* This call makes a copy of our local Terminal variable.
|
|
|
|
*/
|
2020-04-10 18:37:28 +00:00
|
|
|
Status = ConDrvAttachTerminal((PCONSOLE)Console, &Terminal);
|
2013-06-23 00:18:47 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2010-05-31 06:28:55 +00:00
|
|
|
{
|
2014-05-03 01:59:28 +00:00
|
|
|
DPRINT1("Failed to register terminal to the given console, Status = 0x%08lx\n", Status);
|
2014-11-22 22:13:08 +00:00
|
|
|
NtClose(Console->InitEvents[INIT_FAILURE]);
|
|
|
|
NtClose(Console->InitEvents[INIT_SUCCESS]);
|
2020-04-10 18:37:28 +00:00
|
|
|
ConDrvDeleteConsole((PCONSOLE)Console);
|
2014-05-03 01:59:28 +00:00
|
|
|
ConSrvDeinitTerminal(&Terminal);
|
2013-06-23 00:18:47 +00:00
|
|
|
return Status;
|
2010-05-31 06:28:55 +00:00
|
|
|
}
|
2015-03-24 23:58:44 +00:00
|
|
|
DPRINT("Terminal attached\n");
|
2010-05-31 06:28:55 +00:00
|
|
|
|
2014-05-04 00:01:48 +00:00
|
|
|
/* All went right, so add the console to the list */
|
2020-04-10 18:37:28 +00:00
|
|
|
#if 0
|
|
|
|
Status = ConDrvInsertConsole((PCONSOLE)Console);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/* Fail */
|
|
|
|
ConDrvDeleteConsole((PCONSOLE)Console);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
#endif
|
2014-05-04 00:01:48 +00:00
|
|
|
Status = InsertConsole(&ConsoleHandle, Console);
|
|
|
|
|
2014-11-22 22:13:08 +00:00
|
|
|
// FIXME! We do not support at all asynchronous console creation!
|
|
|
|
NtSetEvent(Console->InitEvents[INIT_SUCCESS], NULL);
|
|
|
|
// NtSetEvent(Console->InitEvents[INIT_FAILURE], NULL);
|
|
|
|
|
[CONSOLE.DLL-KERNEL32-CONSRV]
Fix the console properties dialog, when launching and transmitting console properties. Before, the properties dialog was directly launched by the console server (consrv), running with CSRSS (System) privileges, what constituted a security hole. Now, I create a remote thread in the running process owning the console for launching the properties dialog (thus it has only user privileges, and not System ones anymore). For that purpose, I basically took the technique described in the following paper (Cesar Cerrudo, "Story of a dumb patch", http://www.argeniss.com/research/MSBugPaper.pdf or http://www.scn.rain.com/~neighorn/PDF/MSBugPaper.pdf), where basically the console server shares the console properties via a shared memory section with the console properties dialog dll. The address of the thread which launches the dialog in the context of the console app is given to the console server the same way as we do for the control handler (called e.g. when you press Ctrl-C, etc...)
Of course this is quite hackish, because you have the GUI interface split between the console server and the console properties dialog dll. Something far more elegant would be to put all the GUI thingie into a dedicated dll or exe, running with the same privileges as the console program itself (a kind of console -- or terminal -- emulator).
[CONSOLE.DLL]
Fix retriving / setting colors.c and other things.
[CONSRV.DLL]
- Fix retrieving / setting console properties from the registry (via the HKCU\Console\* keys), via the shell shortcuts (not totally done at the moment, because somebody has to implement properly that thing : http://msdn.microsoft.com/en-us/library/windows/desktop/bb773359(v=vs.85).aspx (NT_CONSOLE_PROPS structure stored as a shortcut data block) (at application launching time), and via the console properties dialog.
- Few DPRINTs removed.
svn path=/branches/ros-csrss/; revision=58415
2013-03-03 15:35:12 +00:00
|
|
|
/* Return the newly created console to the caller and a success code too */
|
2013-07-06 19:47:53 +00:00
|
|
|
*NewConsoleHandle = ConsoleHandle;
|
|
|
|
*NewConsole = Console;
|
2010-05-31 06:28:55 +00:00
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2013-10-12 15:44:22 +00:00
|
|
|
VOID NTAPI
|
2014-08-12 14:59:13 +00:00
|
|
|
ConSrvDeleteConsole(PCONSRV_CONSOLE Console)
|
2013-01-24 22:41:33 +00:00
|
|
|
{
|
2013-04-06 13:40:34 +00:00
|
|
|
DPRINT("ConSrvDeleteConsole\n");
|
2013-01-24 22:41:33 +00:00
|
|
|
|
2020-04-10 18:37:28 +00:00
|
|
|
// FIXME: Send a terminate message to all the processes owning this console.
|
|
|
|
// NOTE: In principle there should be none, because such processes would
|
|
|
|
// have a reference to the console and thus this function would not have
|
|
|
|
// been called in the first place.
|
2014-05-04 00:01:48 +00:00
|
|
|
|
|
|
|
/* Remove the console from the list */
|
|
|
|
RemoveConsoleByPointer(Console);
|
|
|
|
|
2014-11-22 22:13:08 +00:00
|
|
|
/* Destroy the Initialization Events */
|
|
|
|
NtClose(Console->InitEvents[INIT_FAILURE]);
|
|
|
|
NtClose(Console->InitEvents[INIT_SUCCESS]);
|
|
|
|
|
2014-08-31 14:04:03 +00:00
|
|
|
/* Clean the Input Line Discipline */
|
|
|
|
if (Console->LineBuffer) ConsoleFreeHeap(Console->LineBuffer);
|
|
|
|
|
2014-05-04 00:01:48 +00:00
|
|
|
/* Clean aliases and history */
|
|
|
|
IntDeleteAllAliases(Console);
|
|
|
|
HistoryDeleteBuffers(Console);
|
|
|
|
|
2014-09-07 22:53:49 +00:00
|
|
|
/* Free the console title */
|
|
|
|
ConsoleFreeUnicodeString(&Console->OriginalTitle);
|
|
|
|
ConsoleFreeUnicodeString(&Console->Title);
|
|
|
|
|
2015-03-24 23:58:44 +00:00
|
|
|
/* Now, call the driver. ConDrvDetachTerminal is called on-demand. */
|
2014-09-05 21:12:42 +00:00
|
|
|
ConDrvDeleteConsole((PCONSOLE)Console);
|
|
|
|
|
|
|
|
/* Deinit the ConSrv terminal */
|
|
|
|
// FIXME!!
|
2014-12-14 21:18:40 +00:00
|
|
|
// ConSrvDeinitTerminal(&Terminal);
|
2013-01-24 22:41:33 +00:00
|
|
|
}
|
|
|
|
|
2013-03-19 22:05:38 +00:00
|
|
|
|
2020-04-10 18:37:28 +00:00
|
|
|
VOID
|
|
|
|
ConioPause(PCONSRV_CONSOLE Console, UCHAR Flags)
|
|
|
|
{
|
|
|
|
Console->PauseFlags |= Flags;
|
|
|
|
ConDrvPause((PCONSOLE)Console);
|
|
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
|
|
ConioUnpause(PCONSRV_CONSOLE Console, UCHAR Flags)
|
|
|
|
{
|
|
|
|
Console->PauseFlags &= ~Flags;
|
|
|
|
|
|
|
|
// if ((Console->PauseFlags & (PAUSED_FROM_KEYBOARD | PAUSED_FROM_SCROLLBAR | PAUSED_FROM_SELECTION)) == 0)
|
|
|
|
if (Console->PauseFlags == 0)
|
|
|
|
{
|
|
|
|
ConDrvUnpause((PCONSOLE)Console);
|
2014-05-02 16:46:13 +00:00
|
|
|
|
2020-04-10 18:37:28 +00:00
|
|
|
CsrNotifyWait(&Console->WriteWaitQueue,
|
|
|
|
TRUE,
|
|
|
|
NULL,
|
|
|
|
NULL);
|
|
|
|
if (!IsListEmpty(&Console->WriteWaitQueue))
|
|
|
|
{
|
|
|
|
CsrDereferenceWait(&Console->WriteWaitQueue);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-05-02 16:46:13 +00:00
|
|
|
|
|
|
|
|
2020-04-13 21:24:55 +00:00
|
|
|
/* CONSOLE PROCESS INITIALIZATION FUNCTIONS ***********************************/
|
|
|
|
|
|
|
|
static NTSTATUS
|
|
|
|
ConSrvInitProcessHandles(
|
|
|
|
IN OUT PCONSOLE_PROCESS_DATA ProcessData,
|
|
|
|
IN PCONSRV_CONSOLE Console,
|
|
|
|
OUT PHANDLE pInputHandle,
|
|
|
|
OUT PHANDLE pOutputHandle,
|
|
|
|
OUT PHANDLE pErrorHandle)
|
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
|
|
|
HANDLE InputHandle = INVALID_HANDLE_VALUE,
|
|
|
|
OutputHandle = INVALID_HANDLE_VALUE,
|
|
|
|
ErrorHandle = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Initialize the process handles. Use temporary variables to store
|
|
|
|
* the handles values in such a way that, if we fail, we don't
|
|
|
|
* return to the caller invalid handle values.
|
|
|
|
*
|
|
|
|
* Insert the IO handles.
|
|
|
|
*/
|
|
|
|
|
|
|
|
RtlEnterCriticalSection(&ProcessData->HandleTableLock);
|
|
|
|
|
|
|
|
/* Insert the Input handle */
|
|
|
|
Status = ConSrvInsertObject(ProcessData,
|
|
|
|
&InputHandle,
|
|
|
|
&Console->InputBuffer.Header,
|
|
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
|
|
TRUE,
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Failed to insert the input handle\n");
|
|
|
|
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
|
|
|
|
ConSrvFreeHandlesTable(ProcessData);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Insert the Output handle */
|
|
|
|
Status = ConSrvInsertObject(ProcessData,
|
|
|
|
&OutputHandle,
|
|
|
|
&Console->ActiveBuffer->Header,
|
|
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
|
|
TRUE,
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Failed to insert the output handle\n");
|
|
|
|
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
|
|
|
|
ConSrvFreeHandlesTable(ProcessData);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Insert the Error handle */
|
|
|
|
Status = ConSrvInsertObject(ProcessData,
|
|
|
|
&ErrorHandle,
|
|
|
|
&Console->ActiveBuffer->Header,
|
|
|
|
GENERIC_READ | GENERIC_WRITE,
|
|
|
|
TRUE,
|
|
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Failed to insert the error handle\n");
|
|
|
|
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
|
|
|
|
ConSrvFreeHandlesTable(ProcessData);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
|
|
|
|
|
|
|
|
/* Return the newly created handles */
|
|
|
|
*pInputHandle = InputHandle;
|
|
|
|
*pOutputHandle = OutputHandle;
|
|
|
|
*pErrorHandle = ErrorHandle;
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
ConSrvAllocateConsole(
|
|
|
|
IN OUT PCONSOLE_PROCESS_DATA ProcessData,
|
|
|
|
OUT PHANDLE pInputHandle,
|
|
|
|
OUT PHANDLE pOutputHandle,
|
|
|
|
OUT PHANDLE pErrorHandle,
|
|
|
|
IN OUT PCONSOLE_INIT_INFO ConsoleInitInfo)
|
|
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
HANDLE ConsoleHandle;
|
|
|
|
PCONSRV_CONSOLE Console;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We are about to create a new console. However when ConSrvNewProcess()
|
|
|
|
* was called, we didn't know that we wanted to create a new console and
|
|
|
|
* therefore, we by default inherited the handle table from our parent
|
|
|
|
* process. It's only now that we notice that in fact we do not need
|
|
|
|
* them, because we've created a new console and thus we must use it.
|
|
|
|
*
|
|
|
|
* Therefore, free the handle table so that we can recreate
|
|
|
|
* a new one later on.
|
|
|
|
*/
|
|
|
|
ConSrvFreeHandlesTable(ProcessData);
|
|
|
|
|
|
|
|
/* Initialize a new Console owned by this process */
|
|
|
|
Status = ConSrvInitConsole(&ConsoleHandle,
|
|
|
|
&Console,
|
|
|
|
ConsoleInitInfo,
|
|
|
|
ProcessData->Process);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Console initialization failed\n");
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Assign the new console handle */
|
|
|
|
ProcessData->ConsoleHandle = ConsoleHandle;
|
|
|
|
|
|
|
|
/* Initialize the process handles */
|
|
|
|
Status = ConSrvInitProcessHandles(ProcessData,
|
|
|
|
Console,
|
|
|
|
pInputHandle,
|
|
|
|
pOutputHandle,
|
|
|
|
pErrorHandle);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Failed to initialize the process handles\n");
|
|
|
|
ConSrvDeleteConsole(Console);
|
|
|
|
ProcessData->ConsoleHandle = NULL;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Duplicate the Initialization Events */
|
|
|
|
Status = NtDuplicateObject(NtCurrentProcess(),
|
|
|
|
Console->InitEvents[INIT_SUCCESS],
|
|
|
|
ProcessData->Process->ProcessHandle,
|
|
|
|
&ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_SUCCESS],
|
|
|
|
EVENT_ALL_ACCESS, 0, 0);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("NtDuplicateObject(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status);
|
|
|
|
ConSrvFreeHandlesTable(ProcessData);
|
|
|
|
ConSrvDeleteConsole(Console);
|
|
|
|
ProcessData->ConsoleHandle = NULL;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = NtDuplicateObject(NtCurrentProcess(),
|
|
|
|
Console->InitEvents[INIT_FAILURE],
|
|
|
|
ProcessData->Process->ProcessHandle,
|
|
|
|
&ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_FAILURE],
|
|
|
|
EVENT_ALL_ACCESS, 0, 0);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("NtDuplicateObject(InitEvents[INIT_FAILURE]) failed: %lu\n", Status);
|
|
|
|
NtDuplicateObject(ProcessData->Process->ProcessHandle,
|
|
|
|
ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_SUCCESS],
|
|
|
|
NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
|
|
|
|
ConSrvFreeHandlesTable(ProcessData);
|
|
|
|
ConSrvDeleteConsole(Console);
|
|
|
|
ProcessData->ConsoleHandle = NULL;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Duplicate the Input Event */
|
|
|
|
Status = NtDuplicateObject(NtCurrentProcess(),
|
|
|
|
Console->InputBuffer.ActiveEvent,
|
|
|
|
ProcessData->Process->ProcessHandle,
|
|
|
|
&ConsoleInitInfo->ConsoleStartInfo->InputWaitHandle,
|
|
|
|
EVENT_ALL_ACCESS, 0, 0);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("NtDuplicateObject(InputWaitHandle) failed: %lu\n", Status);
|
|
|
|
NtDuplicateObject(ProcessData->Process->ProcessHandle,
|
|
|
|
ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_FAILURE],
|
|
|
|
NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
|
|
|
|
NtDuplicateObject(ProcessData->Process->ProcessHandle,
|
|
|
|
ConsoleInitInfo->ConsoleStartInfo->InitEvents[INIT_SUCCESS],
|
|
|
|
NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
|
|
|
|
ConSrvFreeHandlesTable(ProcessData);
|
|
|
|
ConSrvDeleteConsole(Console);
|
|
|
|
ProcessData->ConsoleHandle = NULL;
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Mark the process as having a console */
|
|
|
|
ProcessData->ConsoleApp = TRUE;
|
|
|
|
ProcessData->Process->Flags |= CsrProcessIsConsoleApp;
|
|
|
|
|
|
|
|
/* Return the console handle to the caller */
|
|
|
|
ConsoleInitInfo->ConsoleStartInfo->ConsoleHandle = ProcessData->ConsoleHandle;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Insert the process into the processes list of the console,
|
|
|
|
* and set its foreground priority.
|
|
|
|
*/
|
|
|
|
InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink);
|
|
|
|
ConSrvSetProcessFocus(ProcessData->Process, Console->HasFocus);
|
|
|
|
|
|
|
|
/* Add a reference count because the process is tied to the console */
|
|
|
|
_InterlockedIncrement(&Console->ReferenceCount);
|
|
|
|
|
|
|
|
/* Update the internal info of the terminal */
|
|
|
|
TermRefreshInternalInfo(Console);
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
ConSrvInheritConsole(
|
|
|
|
IN OUT PCONSOLE_PROCESS_DATA ProcessData,
|
|
|
|
IN HANDLE ConsoleHandle,
|
|
|
|
IN BOOLEAN CreateNewHandleTable,
|
|
|
|
OUT PHANDLE pInputHandle,
|
|
|
|
OUT PHANDLE pOutputHandle,
|
|
|
|
OUT PHANDLE pErrorHandle,
|
|
|
|
IN OUT PCONSOLE_START_INFO ConsoleStartInfo)
|
|
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PCONSRV_CONSOLE Console;
|
|
|
|
|
|
|
|
/* Validate and lock the console */
|
|
|
|
if (!ConSrvValidateConsole(&Console,
|
|
|
|
ConsoleHandle,
|
|
|
|
CONSOLE_RUNNING, TRUE))
|
|
|
|
{
|
|
|
|
// FIXME: Find another status code
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Inherit the console */
|
|
|
|
ProcessData->ConsoleHandle = ConsoleHandle;
|
|
|
|
|
|
|
|
if (CreateNewHandleTable)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* We are about to create a new console. However when ConSrvNewProcess()
|
|
|
|
* was called, we didn't know that we wanted to create a new console and
|
|
|
|
* therefore, we by default inherited the handle table from our parent
|
|
|
|
* process. It's only now that we notice that in fact we do not need
|
|
|
|
* them, because we've created a new console and thus we must use it.
|
|
|
|
*
|
|
|
|
* Therefore, free the handle table so that we can recreate
|
|
|
|
* a new one later on.
|
|
|
|
*/
|
|
|
|
ConSrvFreeHandlesTable(ProcessData);
|
|
|
|
|
|
|
|
/* Initialize the process handles */
|
|
|
|
Status = ConSrvInitProcessHandles(ProcessData,
|
|
|
|
Console,
|
|
|
|
pInputHandle,
|
|
|
|
pOutputHandle,
|
|
|
|
pErrorHandle);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("Failed to initialize the process handles\n");
|
|
|
|
ProcessData->ConsoleHandle = NULL;
|
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Duplicate the Initialization Events */
|
|
|
|
Status = NtDuplicateObject(NtCurrentProcess(),
|
|
|
|
Console->InitEvents[INIT_SUCCESS],
|
|
|
|
ProcessData->Process->ProcessHandle,
|
|
|
|
&ConsoleStartInfo->InitEvents[INIT_SUCCESS],
|
|
|
|
EVENT_ALL_ACCESS, 0, 0);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("NtDuplicateObject(InitEvents[INIT_SUCCESS]) failed: %lu\n", Status);
|
|
|
|
ConSrvFreeHandlesTable(ProcessData);
|
|
|
|
ProcessData->ConsoleHandle = NULL;
|
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
|
|
|
Status = NtDuplicateObject(NtCurrentProcess(),
|
|
|
|
Console->InitEvents[INIT_FAILURE],
|
|
|
|
ProcessData->Process->ProcessHandle,
|
|
|
|
&ConsoleStartInfo->InitEvents[INIT_FAILURE],
|
|
|
|
EVENT_ALL_ACCESS, 0, 0);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("NtDuplicateObject(InitEvents[INIT_FAILURE]) failed: %lu\n", Status);
|
|
|
|
NtDuplicateObject(ProcessData->Process->ProcessHandle,
|
|
|
|
ConsoleStartInfo->InitEvents[INIT_SUCCESS],
|
|
|
|
NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
|
|
|
|
ConSrvFreeHandlesTable(ProcessData);
|
|
|
|
ProcessData->ConsoleHandle = NULL;
|
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Duplicate the Input Event */
|
|
|
|
Status = NtDuplicateObject(NtCurrentProcess(),
|
|
|
|
Console->InputBuffer.ActiveEvent,
|
|
|
|
ProcessData->Process->ProcessHandle,
|
|
|
|
&ConsoleStartInfo->InputWaitHandle,
|
|
|
|
EVENT_ALL_ACCESS, 0, 0);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
DPRINT1("NtDuplicateObject(InputWaitHandle) failed: %lu\n", Status);
|
|
|
|
NtDuplicateObject(ProcessData->Process->ProcessHandle,
|
|
|
|
ConsoleStartInfo->InitEvents[INIT_FAILURE],
|
|
|
|
NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
|
|
|
|
NtDuplicateObject(ProcessData->Process->ProcessHandle,
|
|
|
|
ConsoleStartInfo->InitEvents[INIT_SUCCESS],
|
|
|
|
NULL, NULL, 0, 0, DUPLICATE_CLOSE_SOURCE);
|
|
|
|
ConSrvFreeHandlesTable(ProcessData); // NOTE: Always free the handle table.
|
|
|
|
ProcessData->ConsoleHandle = NULL;
|
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Mark the process as having a console */
|
|
|
|
ProcessData->ConsoleApp = TRUE;
|
|
|
|
ProcessData->Process->Flags |= CsrProcessIsConsoleApp;
|
|
|
|
|
|
|
|
/* Return the console handle to the caller */
|
|
|
|
ConsoleStartInfo->ConsoleHandle = ProcessData->ConsoleHandle;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Insert the process into the processes list of the console,
|
|
|
|
* and set its foreground priority.
|
|
|
|
*/
|
|
|
|
InsertHeadList(&Console->ProcessList, &ProcessData->ConsoleLink);
|
|
|
|
ConSrvSetProcessFocus(ProcessData->Process, Console->HasFocus);
|
|
|
|
|
|
|
|
/* Add a reference count because the process is tied to the console */
|
|
|
|
_InterlockedIncrement(&Console->ReferenceCount);
|
|
|
|
|
|
|
|
/* Update the internal info of the terminal */
|
|
|
|
TermRefreshInternalInfo(Console);
|
|
|
|
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
|
|
|
|
Quit:
|
|
|
|
/* Unlock the console and return */
|
|
|
|
LeaveCriticalSection(&Console->Lock);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
ConSrvRemoveConsole(
|
|
|
|
IN OUT PCONSOLE_PROCESS_DATA ProcessData)
|
|
|
|
{
|
|
|
|
PCONSRV_CONSOLE Console;
|
|
|
|
PCONSOLE_PROCESS_DATA ConsoleLeaderProcess;
|
|
|
|
|
|
|
|
DPRINT("ConSrvRemoveConsole\n");
|
|
|
|
|
|
|
|
/* Mark the process as not having a console anymore */
|
|
|
|
ProcessData->ConsoleApp = FALSE;
|
|
|
|
ProcessData->Process->Flags &= ~CsrProcessIsConsoleApp;
|
|
|
|
|
|
|
|
/* Validate and lock the console */
|
|
|
|
if (!ConSrvValidateConsole(&Console,
|
|
|
|
ProcessData->ConsoleHandle,
|
|
|
|
CONSOLE_RUNNING, TRUE))
|
|
|
|
{
|
|
|
|
// FIXME: Find another status code
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
}
|
|
|
|
|
|
|
|
DPRINT("ConSrvRemoveConsole - Locking OK\n");
|
|
|
|
|
|
|
|
/* Retrieve the console leader process */
|
|
|
|
ConsoleLeaderProcess = ConSrvGetConsoleLeaderProcess(Console);
|
|
|
|
|
|
|
|
/* Close all console handles and free the handle table */
|
|
|
|
ConSrvFreeHandlesTable(ProcessData);
|
|
|
|
|
|
|
|
/* Detach the process from the console */
|
|
|
|
ProcessData->ConsoleHandle = NULL;
|
|
|
|
|
|
|
|
/* Remove the process from the console's list of processes */
|
|
|
|
RemoveEntryList(&ProcessData->ConsoleLink);
|
|
|
|
|
|
|
|
/* Check whether the console should send a last close notification */
|
|
|
|
if (Console->NotifyLastClose)
|
|
|
|
{
|
|
|
|
/* If we are removing the process which wants the last close notification... */
|
|
|
|
if (ProcessData == Console->NotifiedLastCloseProcess)
|
|
|
|
{
|
|
|
|
/* ... just reset the flag and the pointer... */
|
|
|
|
Console->NotifyLastClose = FALSE;
|
|
|
|
Console->NotifiedLastCloseProcess = NULL;
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* ... otherwise, if we are removing the console leader process
|
|
|
|
* (that cannot be the process wanting the notification, because
|
|
|
|
* the previous case already dealt with it)...
|
|
|
|
*/
|
|
|
|
else if (ProcessData == ConsoleLeaderProcess)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* ... reset the flag first (so that we avoid multiple notifications)
|
|
|
|
* and then send the last close notification.
|
|
|
|
*/
|
|
|
|
Console->NotifyLastClose = FALSE;
|
|
|
|
ConSrvConsoleCtrlEvent(CTRL_LAST_CLOSE_EVENT, Console->NotifiedLastCloseProcess);
|
|
|
|
|
|
|
|
/* Only now, reset the pointer */
|
|
|
|
Console->NotifiedLastCloseProcess = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Update the internal info of the terminal */
|
|
|
|
TermRefreshInternalInfo(Console);
|
|
|
|
|
|
|
|
/* Release the console */
|
|
|
|
DPRINT("ConSrvRemoveConsole - Decrement Console->ReferenceCount = %lu\n", Console->ReferenceCount);
|
|
|
|
ConSrvReleaseConsole(Console, TRUE);
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2020-04-10 18:37:28 +00:00
|
|
|
/* CONSOLE PROCESS MANAGEMENT FUNCTIONS ***************************************/
|
2014-05-02 16:46:13 +00:00
|
|
|
|
2019-01-03 12:26:57 +00:00
|
|
|
NTSTATUS
|
2014-05-02 16:46:13 +00:00
|
|
|
ConSrvConsoleCtrlEventTimeout(IN ULONG CtrlEvent,
|
|
|
|
IN PCONSOLE_PROCESS_DATA ProcessData,
|
|
|
|
IN ULONG Timeout)
|
|
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
|
|
|
|
DPRINT("ConSrvConsoleCtrlEventTimeout Parent ProcessId = %x\n", ProcessData->Process->ClientId.UniqueProcess);
|
|
|
|
|
2015-03-24 23:58:44 +00:00
|
|
|
/*
|
|
|
|
* Be sure we effectively have a control routine. It resides in kernel32.dll (client).
|
|
|
|
*/
|
|
|
|
if (ProcessData->CtrlRoutine == NULL) return Status;
|
|
|
|
|
|
|
|
_SEH2_TRY
|
2014-05-02 16:46:13 +00:00
|
|
|
{
|
2015-03-24 23:58:44 +00:00
|
|
|
HANDLE Thread = NULL;
|
|
|
|
|
2014-05-02 16:46:13 +00:00
|
|
|
_SEH2_TRY
|
|
|
|
{
|
2015-03-24 23:58:44 +00:00
|
|
|
Thread = CreateRemoteThread(ProcessData->Process->ProcessHandle, NULL, 0,
|
|
|
|
ProcessData->CtrlRoutine,
|
|
|
|
UlongToPtr(CtrlEvent), 0, NULL);
|
|
|
|
if (NULL == Thread)
|
2014-05-02 16:46:13 +00:00
|
|
|
{
|
2015-03-24 23:58:44 +00:00
|
|
|
Status = RtlGetLastNtStatus();
|
|
|
|
DPRINT1("Failed thread creation, Status = 0x%08lx\n", Status);
|
2014-05-02 16:46:13 +00:00
|
|
|
}
|
2015-03-24 23:58:44 +00:00
|
|
|
else
|
2014-05-02 16:46:13 +00:00
|
|
|
{
|
2015-03-24 23:58:44 +00:00
|
|
|
DPRINT("ProcessData->CtrlRoutine remote thread creation succeeded, ProcessId = %x, Process = 0x%p\n",
|
|
|
|
ProcessData->Process->ClientId.UniqueProcess, ProcessData->Process);
|
|
|
|
WaitForSingleObject(Thread, Timeout);
|
2014-05-02 16:46:13 +00:00
|
|
|
}
|
|
|
|
}
|
2015-03-24 23:58:44 +00:00
|
|
|
_SEH2_FINALLY
|
2014-05-02 16:46:13 +00:00
|
|
|
{
|
2015-03-24 23:58:44 +00:00
|
|
|
CloseHandle(Thread);
|
2014-05-02 16:46:13 +00:00
|
|
|
}
|
|
|
|
_SEH2_END;
|
|
|
|
}
|
2015-03-24 23:58:44 +00:00
|
|
|
_SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
|
|
|
|
{
|
|
|
|
Status = _SEH2_GetExceptionCode();
|
|
|
|
DPRINT1("ConSrvConsoleCtrlEventTimeout - Caught an exception, Status = 0x%08lx\n", Status);
|
|
|
|
}
|
|
|
|
_SEH2_END;
|
2014-05-02 16:46:13 +00:00
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
|
|
ConSrvConsoleCtrlEvent(IN ULONG CtrlEvent,
|
|
|
|
IN PCONSOLE_PROCESS_DATA ProcessData)
|
|
|
|
{
|
|
|
|
return ConSrvConsoleCtrlEventTimeout(CtrlEvent, ProcessData, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
PCONSOLE_PROCESS_DATA NTAPI
|
2014-08-11 20:28:40 +00:00
|
|
|
ConSrvGetConsoleLeaderProcess(IN PCONSRV_CONSOLE Console)
|
2014-05-02 16:46:13 +00:00
|
|
|
{
|
|
|
|
if (Console == NULL) return NULL;
|
|
|
|
|
|
|
|
return CONTAINING_RECORD(Console->ProcessList.Blink,
|
|
|
|
CONSOLE_PROCESS_DATA,
|
|
|
|
ConsoleLink);
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS NTAPI
|
2014-08-12 14:59:13 +00:00
|
|
|
ConSrvGetConsoleProcessList(IN PCONSRV_CONSOLE Console,
|
2014-05-02 16:46:13 +00:00
|
|
|
IN OUT PULONG ProcessIdsList,
|
|
|
|
IN ULONG MaxIdListItems,
|
|
|
|
OUT PULONG ProcessIdsTotal)
|
|
|
|
{
|
|
|
|
PCONSOLE_PROCESS_DATA current;
|
|
|
|
PLIST_ENTRY current_entry;
|
|
|
|
|
|
|
|
if (Console == NULL || ProcessIdsList == NULL || ProcessIdsTotal == NULL)
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
|
|
|
|
*ProcessIdsTotal = 0;
|
|
|
|
|
|
|
|
for (current_entry = Console->ProcessList.Flink;
|
|
|
|
current_entry != &Console->ProcessList;
|
|
|
|
current_entry = current_entry->Flink)
|
|
|
|
{
|
|
|
|
current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
|
|
|
|
if (++(*ProcessIdsTotal) <= MaxIdListItems)
|
|
|
|
{
|
|
|
|
*ProcessIdsList++ = HandleToUlong(current->Process->ClientId.UniqueProcess);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ConSrvGenerateConsoleCtrlEvent
|
|
|
|
NTSTATUS NTAPI
|
2014-08-11 20:28:40 +00:00
|
|
|
ConSrvConsoleProcessCtrlEvent(IN PCONSRV_CONSOLE Console,
|
2014-05-02 16:46:13 +00:00
|
|
|
IN ULONG ProcessGroupId,
|
|
|
|
IN ULONG CtrlEvent)
|
|
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PLIST_ENTRY current_entry;
|
|
|
|
PCONSOLE_PROCESS_DATA current;
|
|
|
|
|
|
|
|
/* If the console is already being destroyed, just return */
|
2014-09-05 21:12:42 +00:00
|
|
|
if (!ConDrvValidateConsoleState((PCONSOLE)Console, CONSOLE_RUNNING))
|
2014-05-02 16:46:13 +00:00
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Loop through the process list, from the most recent process
|
|
|
|
* (the active one) to the oldest one (the first created, i.e.
|
|
|
|
* the console leader process), and for each, send an event
|
|
|
|
* (new processes are inserted at the head of the console process list).
|
|
|
|
*/
|
|
|
|
current_entry = Console->ProcessList.Flink;
|
|
|
|
while (current_entry != &Console->ProcessList)
|
|
|
|
{
|
|
|
|
current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
|
|
|
|
current_entry = current_entry->Flink;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Only processes belonging to the same process group are signaled.
|
|
|
|
* If the process group ID is zero, then all the processes are signaled.
|
|
|
|
*/
|
|
|
|
if (ProcessGroupId == 0 || current->Process->ProcessGroupId == ProcessGroupId)
|
|
|
|
{
|
|
|
|
Status = ConSrvConsoleCtrlEvent(CtrlEvent, current);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2015-08-15 17:05:13 +00:00
|
|
|
VOID
|
|
|
|
ConSrvSetProcessFocus(IN PCSR_PROCESS CsrProcess,
|
|
|
|
IN BOOLEAN SetForeground)
|
|
|
|
{
|
|
|
|
// FIXME: Call NtUserSetInformationProcess (currently unimplemented!)
|
|
|
|
// for setting Win32 foreground/background flags.
|
|
|
|
|
|
|
|
if (SetForeground)
|
|
|
|
CsrSetForegroundPriority(CsrProcess);
|
|
|
|
else
|
|
|
|
CsrSetBackgroundPriority(CsrProcess);
|
|
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS NTAPI
|
|
|
|
ConSrvSetConsoleProcessFocus(IN PCONSRV_CONSOLE Console,
|
|
|
|
IN BOOLEAN SetForeground)
|
|
|
|
{
|
|
|
|
PLIST_ENTRY current_entry;
|
|
|
|
PCONSOLE_PROCESS_DATA current;
|
|
|
|
|
|
|
|
/* If the console is already being destroyed, just return */
|
|
|
|
if (!ConDrvValidateConsoleState((PCONSOLE)Console, CONSOLE_RUNNING))
|
|
|
|
return STATUS_UNSUCCESSFUL;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Loop through the process list, from the most recent process
|
|
|
|
* to the oldest one, and for each, set its foreground priority.
|
|
|
|
*/
|
|
|
|
current_entry = Console->ProcessList.Flink;
|
|
|
|
while (current_entry != &Console->ProcessList)
|
|
|
|
{
|
|
|
|
current = CONTAINING_RECORD(current_entry, CONSOLE_PROCESS_DATA, ConsoleLink);
|
|
|
|
current_entry = current_entry->Flink;
|
|
|
|
|
|
|
|
ConSrvSetProcessFocus(current->Process, SetForeground);
|
|
|
|
}
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2014-05-02 16:46:13 +00:00
|
|
|
|
2013-03-19 22:05:38 +00:00
|
|
|
/* PUBLIC SERVER APIS *********************************************************/
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepAlloc */
|
2020-04-12 10:45:31 +00:00
|
|
|
CON_API_NOCONSOLE(SrvAllocConsole,
|
|
|
|
CONSOLE_ALLOCCONSOLE, AllocConsoleRequest)
|
2010-05-31 06:28:55 +00:00
|
|
|
{
|
2012-11-18 13:10:03 +00:00
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
2014-09-07 22:53:49 +00:00
|
|
|
CONSOLE_INIT_INFO ConsoleInitInfo;
|
2010-05-31 06:28:55 +00:00
|
|
|
|
2013-07-06 19:47:53 +00:00
|
|
|
if (ProcessData->ConsoleHandle != NULL)
|
2010-05-31 06:28:55 +00:00
|
|
|
{
|
|
|
|
DPRINT1("Process already has a console\n");
|
2013-01-13 17:07:25 +00:00
|
|
|
return STATUS_ACCESS_DENIED;
|
2010-05-31 06:28:55 +00:00
|
|
|
}
|
|
|
|
|
2014-09-07 22:53:49 +00:00
|
|
|
if ( !CsrValidateMessageBuffer(ApiMessage,
|
|
|
|
(PVOID*)&AllocConsoleRequest->ConsoleStartInfo,
|
|
|
|
1,
|
|
|
|
sizeof(CONSOLE_START_INFO)) ||
|
|
|
|
!CsrValidateMessageBuffer(ApiMessage,
|
|
|
|
(PVOID*)&AllocConsoleRequest->ConsoleTitle,
|
|
|
|
AllocConsoleRequest->TitleLength,
|
|
|
|
sizeof(BYTE)) ||
|
|
|
|
!CsrValidateMessageBuffer(ApiMessage,
|
|
|
|
(PVOID*)&AllocConsoleRequest->Desktop,
|
|
|
|
AllocConsoleRequest->DesktopLength,
|
|
|
|
sizeof(BYTE)) ||
|
|
|
|
!CsrValidateMessageBuffer(ApiMessage,
|
|
|
|
(PVOID*)&AllocConsoleRequest->CurDir,
|
|
|
|
AllocConsoleRequest->CurDirLength,
|
|
|
|
sizeof(BYTE)) ||
|
|
|
|
!CsrValidateMessageBuffer(ApiMessage,
|
|
|
|
(PVOID*)&AllocConsoleRequest->AppName,
|
|
|
|
AllocConsoleRequest->AppNameLength,
|
|
|
|
sizeof(BYTE)) )
|
2013-02-10 12:36:57 +00:00
|
|
|
{
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
2014-09-07 22:53:49 +00:00
|
|
|
/* Initialize the console initialization info structure */
|
|
|
|
ConsoleInitInfo.ConsoleStartInfo = AllocConsoleRequest->ConsoleStartInfo;
|
2014-11-23 23:04:45 +00:00
|
|
|
ConsoleInitInfo.IsWindowVisible = TRUE; // The console window is always visible.
|
2014-09-07 22:53:49 +00:00
|
|
|
ConsoleInitInfo.TitleLength = AllocConsoleRequest->TitleLength;
|
|
|
|
ConsoleInitInfo.ConsoleTitle = AllocConsoleRequest->ConsoleTitle;
|
|
|
|
ConsoleInitInfo.DesktopLength = AllocConsoleRequest->DesktopLength;
|
|
|
|
ConsoleInitInfo.Desktop = AllocConsoleRequest->Desktop;
|
|
|
|
ConsoleInitInfo.AppNameLength = AllocConsoleRequest->AppNameLength;
|
|
|
|
ConsoleInitInfo.AppName = AllocConsoleRequest->AppName;
|
|
|
|
ConsoleInitInfo.CurDirLength = AllocConsoleRequest->CurDirLength;
|
|
|
|
ConsoleInitInfo.CurDir = AllocConsoleRequest->CurDir;
|
|
|
|
|
2013-01-04 00:41:10 +00:00
|
|
|
/* Initialize a new Console owned by the Console Leader Process */
|
2013-01-24 22:41:33 +00:00
|
|
|
Status = ConSrvAllocateConsole(ProcessData,
|
2014-09-07 22:53:49 +00:00
|
|
|
&AllocConsoleRequest->ConsoleStartInfo->InputHandle,
|
|
|
|
&AllocConsoleRequest->ConsoleStartInfo->OutputHandle,
|
|
|
|
&AllocConsoleRequest->ConsoleStartInfo->ErrorHandle,
|
|
|
|
&ConsoleInitInfo);
|
2013-01-02 00:32:20 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
2010-05-31 06:28:55 +00:00
|
|
|
{
|
2013-01-16 22:25:12 +00:00
|
|
|
DPRINT1("Console allocation failed\n");
|
2013-01-02 00:32:20 +00:00
|
|
|
return Status;
|
2010-05-31 06:28:55 +00:00
|
|
|
}
|
|
|
|
|
2013-07-06 19:47:53 +00:00
|
|
|
/* Set the Property-Dialog and Control-Dispatcher handlers */
|
2014-09-07 22:53:49 +00:00
|
|
|
ProcessData->PropRoutine = AllocConsoleRequest->PropRoutine;
|
|
|
|
ProcessData->CtrlRoutine = AllocConsoleRequest->CtrlRoutine;
|
2010-05-31 06:28:55 +00:00
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
|
|
|
}
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepAttach */
|
2020-04-12 10:45:31 +00:00
|
|
|
CON_API_NOCONSOLE(SrvAttachConsole,
|
|
|
|
CONSOLE_ATTACHCONSOLE, AttachConsoleRequest)
|
2013-01-13 17:07:25 +00:00
|
|
|
{
|
|
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PCSR_PROCESS SourceProcess = NULL; // The parent process.
|
|
|
|
PCSR_PROCESS TargetProcess = CsrGetClientThread()->Process; // Ourselves.
|
|
|
|
HANDLE ProcessId = ULongToHandle(AttachConsoleRequest->ProcessId);
|
|
|
|
PCONSOLE_PROCESS_DATA SourceProcessData, TargetProcessData;
|
|
|
|
|
|
|
|
TargetProcessData = ConsoleGetPerProcessData(TargetProcess);
|
|
|
|
|
2013-07-06 19:47:53 +00:00
|
|
|
if (TargetProcessData->ConsoleHandle != NULL)
|
2013-01-13 17:07:25 +00:00
|
|
|
{
|
|
|
|
DPRINT1("Process already has a console\n");
|
|
|
|
return STATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
|
2014-09-07 22:53:49 +00:00
|
|
|
if (!CsrValidateMessageBuffer(ApiMessage,
|
|
|
|
(PVOID*)&AttachConsoleRequest->ConsoleStartInfo,
|
|
|
|
1,
|
|
|
|
sizeof(CONSOLE_START_INFO)))
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
2013-02-01 23:36:23 +00:00
|
|
|
/* Check whether we try to attach to the parent's console */
|
2013-01-13 17:07:25 +00:00
|
|
|
if (ProcessId == ULongToHandle(ATTACH_PARENT_PROCESS))
|
|
|
|
{
|
|
|
|
PROCESS_BASIC_INFORMATION ProcessInfo;
|
|
|
|
ULONG Length = sizeof(ProcessInfo);
|
|
|
|
|
2015-04-05 23:04:42 +00:00
|
|
|
/* Get the real parent's PID */
|
2013-01-13 17:07:25 +00:00
|
|
|
|
|
|
|
Status = NtQueryInformationProcess(TargetProcess->ProcessHandle,
|
|
|
|
ProcessBasicInformation,
|
|
|
|
&ProcessInfo,
|
|
|
|
Length, &Length);
|
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2014-12-04 23:15:18 +00:00
|
|
|
DPRINT1("SrvAttachConsole - Cannot retrieve basic process info, Status = 0x%08lx\n", Status);
|
2013-01-13 17:07:25 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
ProcessId = ULongToHandle(ProcessInfo.InheritedFromUniqueProcessId);
|
|
|
|
}
|
|
|
|
|
2013-02-01 23:36:23 +00:00
|
|
|
/* Lock the source process via its PID */
|
2013-01-13 17:07:25 +00:00
|
|
|
Status = CsrLockProcessByClientId(ProcessId, &SourceProcess);
|
|
|
|
if (!NT_SUCCESS(Status)) return Status;
|
|
|
|
|
|
|
|
SourceProcessData = ConsoleGetPerProcessData(SourceProcess);
|
|
|
|
|
2013-07-06 19:47:53 +00:00
|
|
|
if (SourceProcessData->ConsoleHandle == NULL)
|
2013-02-01 23:36:23 +00:00
|
|
|
{
|
|
|
|
Status = STATUS_INVALID_HANDLE;
|
|
|
|
goto Quit;
|
|
|
|
}
|
|
|
|
|
2013-01-13 17:07:25 +00:00
|
|
|
/*
|
|
|
|
* Inherit the console from the parent,
|
|
|
|
* if any, otherwise return an error.
|
|
|
|
*/
|
2013-02-01 23:36:23 +00:00
|
|
|
Status = ConSrvInheritConsole(TargetProcessData,
|
2013-07-06 19:47:53 +00:00
|
|
|
SourceProcessData->ConsoleHandle,
|
2013-02-01 23:36:23 +00:00
|
|
|
TRUE,
|
2014-09-07 22:53:49 +00:00
|
|
|
&AttachConsoleRequest->ConsoleStartInfo->InputHandle,
|
|
|
|
&AttachConsoleRequest->ConsoleStartInfo->OutputHandle,
|
2014-11-22 22:13:08 +00:00
|
|
|
&AttachConsoleRequest->ConsoleStartInfo->ErrorHandle,
|
|
|
|
AttachConsoleRequest->ConsoleStartInfo);
|
2013-01-13 17:07:25 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
{
|
2013-02-01 23:36:23 +00:00
|
|
|
DPRINT1("Console inheritance failed\n");
|
2013-01-13 17:07:25 +00:00
|
|
|
goto Quit;
|
|
|
|
}
|
2013-01-16 22:25:12 +00:00
|
|
|
|
2013-07-06 19:47:53 +00:00
|
|
|
/* Set the Property-Dialog and Control-Dispatcher handlers */
|
2014-09-07 22:53:49 +00:00
|
|
|
TargetProcessData->PropRoutine = AttachConsoleRequest->PropRoutine;
|
|
|
|
TargetProcessData->CtrlRoutine = AttachConsoleRequest->CtrlRoutine;
|
2013-01-13 17:07:25 +00:00
|
|
|
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
|
|
|
|
Quit:
|
2013-02-01 23:36:23 +00:00
|
|
|
/* Unlock the "source" process and exit */
|
2013-01-13 17:07:25 +00:00
|
|
|
CsrUnlockProcess(SourceProcess);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepFree */
|
2020-04-12 10:45:31 +00:00
|
|
|
CON_API_NOCONSOLE(SrvFreeConsole,
|
|
|
|
CONSOLE_FREECONSOLE, FreeConsoleRequest)
|
2010-05-31 06:28:55 +00:00
|
|
|
{
|
2020-04-12 10:45:31 +00:00
|
|
|
/*
|
|
|
|
* If this process doesn't have a console handle, bail out immediately.
|
|
|
|
* Also the passed console handle should be the same as the process' one.
|
|
|
|
*/
|
|
|
|
if ((FreeConsoleRequest->ConsoleHandle == NULL) ||
|
|
|
|
(FreeConsoleRequest->ConsoleHandle != ProcessData->ConsoleHandle))
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_HANDLE; // STATUS_ACCESS_DENIED;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ConSrvRemoveConsole(ProcessData);
|
2010-05-31 06:28:55 +00:00
|
|
|
}
|
|
|
|
|
2013-06-23 00:18:47 +00:00
|
|
|
NTSTATUS NTAPI
|
|
|
|
ConDrvGetConsoleMode(IN PCONSOLE Console,
|
|
|
|
IN PCONSOLE_IO_OBJECT Object,
|
|
|
|
OUT PULONG ConsoleMode);
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepGetMode */
|
2020-04-12 10:45:31 +00:00
|
|
|
CON_API(SrvGetConsoleMode,
|
|
|
|
CONSOLE_GETSETCONSOLEMODE, ConsoleModeRequest)
|
2013-04-07 23:39:39 +00:00
|
|
|
{
|
|
|
|
NTSTATUS Status;
|
2013-06-23 00:18:47 +00:00
|
|
|
PCONSOLE_IO_OBJECT Object;
|
2014-08-29 19:45:45 +00:00
|
|
|
PULONG ConsoleMode = &ConsoleModeRequest->Mode;
|
|
|
|
|
2020-04-12 10:45:31 +00:00
|
|
|
Status = ConSrvGetObject(ProcessData,
|
2014-04-20 11:25:38 +00:00
|
|
|
ConsoleModeRequest->Handle,
|
2013-04-07 23:39:39 +00:00
|
|
|
&Object, NULL, GENERIC_READ, TRUE, 0);
|
2020-04-12 10:45:31 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
return Status;
|
2013-04-07 23:39:39 +00:00
|
|
|
|
2020-04-12 10:45:31 +00:00
|
|
|
ASSERT((PCONSOLE)Console == Object->Console);
|
2020-04-10 18:37:28 +00:00
|
|
|
|
2014-08-29 19:45:45 +00:00
|
|
|
/* Get the standard console modes */
|
2020-04-12 10:45:31 +00:00
|
|
|
Status = ConDrvGetConsoleMode((PCONSOLE)Console, Object, ConsoleMode);
|
2014-08-29 19:45:45 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If getting the console modes succeeds, then retrieve
|
|
|
|
* the extended CONSRV-specific input modes.
|
|
|
|
*/
|
|
|
|
if (INPUT_BUFFER == Object->Type)
|
|
|
|
{
|
2020-04-10 18:37:28 +00:00
|
|
|
if (Console->InsertMode || Console->QuickEdit)
|
2014-08-29 19:45:45 +00:00
|
|
|
{
|
2014-09-05 21:12:42 +00:00
|
|
|
/* Windows also adds ENABLE_EXTENDED_FLAGS, even if it's not documented on MSDN */
|
2014-08-29 19:45:45 +00:00
|
|
|
*ConsoleMode |= ENABLE_EXTENDED_FLAGS;
|
|
|
|
|
2020-04-10 18:37:28 +00:00
|
|
|
if (Console->InsertMode) *ConsoleMode |= ENABLE_INSERT_MODE;
|
|
|
|
if (Console->QuickEdit ) *ConsoleMode |= ENABLE_QUICK_EDIT_MODE;
|
2014-08-29 19:45:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-04-07 23:39:39 +00:00
|
|
|
|
|
|
|
ConSrvReleaseObject(Object, TRUE);
|
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2013-06-23 00:18:47 +00:00
|
|
|
NTSTATUS NTAPI
|
|
|
|
ConDrvSetConsoleMode(IN PCONSOLE Console,
|
|
|
|
IN PCONSOLE_IO_OBJECT Object,
|
|
|
|
IN ULONG ConsoleMode);
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepSetMode */
|
2020-04-12 10:45:31 +00:00
|
|
|
CON_API(SrvSetConsoleMode,
|
|
|
|
CONSOLE_GETSETCONSOLEMODE, ConsoleModeRequest)
|
2010-05-31 06:28:55 +00:00
|
|
|
{
|
2014-08-29 19:45:45 +00:00
|
|
|
#define CONSOLE_VALID_CONTROL_MODES ( ENABLE_EXTENDED_FLAGS | \
|
|
|
|
ENABLE_INSERT_MODE | ENABLE_QUICK_EDIT_MODE )
|
2020-02-08 23:18:40 +00:00
|
|
|
// NOTE: Vista+ ENABLE_AUTO_POSITION is also a control mode.
|
2014-08-29 19:45:45 +00:00
|
|
|
|
2010-05-31 06:28:55 +00:00
|
|
|
NTSTATUS Status;
|
2013-06-23 00:18:47 +00:00
|
|
|
PCONSOLE_IO_OBJECT Object;
|
2014-08-29 19:45:45 +00:00
|
|
|
ULONG ConsoleMode = ConsoleModeRequest->Mode;
|
|
|
|
|
2020-04-12 10:45:31 +00:00
|
|
|
Status = ConSrvGetObject(ProcessData,
|
2014-04-20 11:25:38 +00:00
|
|
|
ConsoleModeRequest->Handle,
|
2013-04-01 00:23:34 +00:00
|
|
|
&Object, NULL, GENERIC_WRITE, TRUE, 0);
|
2020-04-12 10:45:31 +00:00
|
|
|
if (!NT_SUCCESS(Status))
|
|
|
|
return Status;
|
2010-05-31 06:28:55 +00:00
|
|
|
|
2020-04-12 10:45:31 +00:00
|
|
|
ASSERT((PCONSOLE)Console == Object->Console);
|
2020-04-10 18:37:28 +00:00
|
|
|
|
2014-08-29 19:45:45 +00:00
|
|
|
/* Set the standard console modes (without the CONSRV-specific input modes) */
|
|
|
|
ConsoleMode &= ~CONSOLE_VALID_CONTROL_MODES; // Remove CONSRV-specific input modes.
|
2020-04-12 10:45:31 +00:00
|
|
|
Status = ConDrvSetConsoleMode((PCONSOLE)Console, Object, ConsoleMode);
|
2014-08-29 19:45:45 +00:00
|
|
|
if (NT_SUCCESS(Status))
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If setting the console modes succeeds, then set
|
|
|
|
* the extended CONSRV-specific input modes.
|
|
|
|
*/
|
|
|
|
if (INPUT_BUFFER == Object->Type)
|
|
|
|
{
|
|
|
|
ConsoleMode = ConsoleModeRequest->Mode;
|
|
|
|
|
|
|
|
if (ConsoleMode & CONSOLE_VALID_CONTROL_MODES)
|
|
|
|
{
|
|
|
|
/*
|
|
|
|
* If we use control mode flags without ENABLE_EXTENDED_FLAGS,
|
|
|
|
* then consider the flags invalid.
|
|
|
|
*/
|
|
|
|
if ((ConsoleMode & ENABLE_EXTENDED_FLAGS) == 0)
|
|
|
|
{
|
|
|
|
Status = STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2020-04-10 18:37:28 +00:00
|
|
|
Console->InsertMode = !!(ConsoleMode & ENABLE_INSERT_MODE);
|
|
|
|
Console->QuickEdit = !!(ConsoleMode & ENABLE_QUICK_EDIT_MODE);
|
2014-08-29 19:45:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-11-17 23:07:59 +00:00
|
|
|
|
2013-01-24 22:41:33 +00:00
|
|
|
ConSrvReleaseObject(Object, TRUE);
|
2010-05-31 06:28:55 +00:00
|
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepGetTitle */
|
2020-04-12 10:45:31 +00:00
|
|
|
CON_API(SrvGetConsoleTitle,
|
|
|
|
CONSOLE_GETSETCONSOLETITLE, TitleRequest)
|
2010-05-31 06:28:55 +00:00
|
|
|
{
|
2014-09-07 22:53:49 +00:00
|
|
|
ULONG Length;
|
2012-11-17 23:07:59 +00:00
|
|
|
|
2013-04-07 23:39:39 +00:00
|
|
|
if (!CsrValidateMessageBuffer(ApiMessage,
|
|
|
|
(PVOID)&TitleRequest->Title,
|
|
|
|
TitleRequest->Length,
|
|
|
|
sizeof(BYTE)))
|
2010-05-31 06:28:55 +00:00
|
|
|
{
|
2013-04-07 23:39:39 +00:00
|
|
|
return STATUS_INVALID_PARAMETER;
|
2010-05-31 06:28:55 +00:00
|
|
|
}
|
2013-04-07 23:39:39 +00:00
|
|
|
|
2014-09-07 22:53:49 +00:00
|
|
|
/* Copy title of the console to the user title buffer */
|
|
|
|
if (TitleRequest->Unicode)
|
|
|
|
{
|
|
|
|
if (TitleRequest->Length >= sizeof(WCHAR))
|
|
|
|
{
|
|
|
|
Length = min(TitleRequest->Length - sizeof(WCHAR), Console->Title.Length);
|
|
|
|
RtlCopyMemory(TitleRequest->Title, Console->Title.Buffer, Length);
|
2015-03-24 23:58:44 +00:00
|
|
|
((PWCHAR)TitleRequest->Title)[Length / sizeof(WCHAR)] = UNICODE_NULL;
|
2014-09-07 22:53:49 +00:00
|
|
|
TitleRequest->Length = Length;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TitleRequest->Length = Console->Title.Length;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (TitleRequest->Length >= sizeof(CHAR))
|
|
|
|
{
|
|
|
|
Length = min(TitleRequest->Length - sizeof(CHAR), Console->Title.Length / sizeof(WCHAR));
|
|
|
|
Length = WideCharToMultiByte(Console->InputCodePage, 0,
|
|
|
|
Console->Title.Buffer, Length,
|
|
|
|
TitleRequest->Title, Length,
|
|
|
|
NULL, NULL);
|
2015-03-24 23:58:44 +00:00
|
|
|
((PCHAR)TitleRequest->Title)[Length] = ANSI_NULL;
|
2014-09-07 22:53:49 +00:00
|
|
|
TitleRequest->Length = Length;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
TitleRequest->Length = Console->Title.Length / sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
}
|
2013-04-07 23:39:39 +00:00
|
|
|
|
2020-04-12 10:45:31 +00:00
|
|
|
return STATUS_SUCCESS;
|
2010-05-31 06:28:55 +00:00
|
|
|
}
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepSetTitle */
|
2020-04-12 10:45:31 +00:00
|
|
|
CON_API(SrvSetConsoleTitle,
|
|
|
|
CONSOLE_GETSETCONSOLETITLE, TitleRequest)
|
2010-05-31 06:28:55 +00:00
|
|
|
{
|
2014-09-07 22:53:49 +00:00
|
|
|
PWCHAR Buffer;
|
|
|
|
ULONG Length;
|
|
|
|
|
2012-11-18 13:10:03 +00:00
|
|
|
if (!CsrValidateMessageBuffer(ApiMessage,
|
|
|
|
(PVOID)&TitleRequest->Title,
|
|
|
|
TitleRequest->Length,
|
|
|
|
sizeof(BYTE)))
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
2010-05-31 06:28:55 +00:00
|
|
|
|
2014-09-07 22:53:49 +00:00
|
|
|
if (TitleRequest->Unicode)
|
|
|
|
{
|
|
|
|
/* Length is in bytes */
|
|
|
|
Length = TitleRequest->Length;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* Use the console input CP for the conversion */
|
|
|
|
Length = MultiByteToWideChar(Console->InputCodePage, 0,
|
|
|
|
TitleRequest->Title, TitleRequest->Length,
|
|
|
|
NULL, 0);
|
|
|
|
/* The returned Length was in number of wchars, convert it in bytes */
|
|
|
|
Length *= sizeof(WCHAR);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Allocate a new buffer to hold the new title (NULL-terminated) */
|
|
|
|
Buffer = ConsoleAllocHeap(HEAP_ZERO_MEMORY, Length + sizeof(WCHAR));
|
|
|
|
if (!Buffer)
|
2020-04-12 10:45:31 +00:00
|
|
|
return STATUS_NO_MEMORY;
|
2014-09-07 22:53:49 +00:00
|
|
|
|
|
|
|
/* Free the old title */
|
|
|
|
ConsoleFreeUnicodeString(&Console->Title);
|
|
|
|
|
|
|
|
/* Copy title to console */
|
|
|
|
Console->Title.Buffer = Buffer;
|
|
|
|
Console->Title.Length = Length;
|
|
|
|
Console->Title.MaximumLength = Console->Title.Length + sizeof(WCHAR);
|
2012-11-18 13:10:03 +00:00
|
|
|
|
2014-09-07 22:53:49 +00:00
|
|
|
if (TitleRequest->Unicode)
|
|
|
|
{
|
|
|
|
RtlCopyMemory(Console->Title.Buffer, TitleRequest->Title, Console->Title.Length);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
MultiByteToWideChar(Console->InputCodePage, 0,
|
|
|
|
TitleRequest->Title, TitleRequest->Length,
|
|
|
|
Console->Title.Buffer,
|
|
|
|
Console->Title.Length / sizeof(WCHAR));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* NULL-terminate */
|
2015-03-24 23:58:44 +00:00
|
|
|
Console->Title.Buffer[Console->Title.Length / sizeof(WCHAR)] = UNICODE_NULL;
|
2014-09-07 22:53:49 +00:00
|
|
|
|
|
|
|
TermChangeTitle(Console);
|
|
|
|
|
2020-04-12 10:45:31 +00:00
|
|
|
return STATUS_SUCCESS;
|
2010-05-31 06:28:55 +00:00
|
|
|
}
|
|
|
|
|
2013-06-23 00:18:47 +00:00
|
|
|
NTSTATUS NTAPI
|
|
|
|
ConDrvGetConsoleCP(IN PCONSOLE Console,
|
|
|
|
OUT PUINT CodePage,
|
2014-03-08 15:31:05 +00:00
|
|
|
IN BOOLEAN OutputCP);
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepGetCP */
|
2020-04-12 10:45:31 +00:00
|
|
|
CON_API(SrvGetConsoleCP,
|
|
|
|
CONSOLE_GETINPUTOUTPUTCP, GetConsoleCPRequest)
|
2010-05-31 06:28:55 +00:00
|
|
|
{
|
2012-11-18 13:10:03 +00:00
|
|
|
DPRINT("SrvGetConsoleCP, getting %s Code Page\n",
|
2014-03-08 15:31:05 +00:00
|
|
|
GetConsoleCPRequest->OutputCP ? "Output" : "Input");
|
2010-05-31 06:28:55 +00:00
|
|
|
|
2020-04-12 10:45:31 +00:00
|
|
|
return ConDrvGetConsoleCP((PCONSOLE)Console,
|
|
|
|
&GetConsoleCPRequest->CodePage,
|
|
|
|
GetConsoleCPRequest->OutputCP);
|
2010-05-31 06:28:55 +00:00
|
|
|
}
|
|
|
|
|
2013-06-23 00:18:47 +00:00
|
|
|
NTSTATUS NTAPI
|
|
|
|
ConDrvSetConsoleCP(IN PCONSOLE Console,
|
|
|
|
IN UINT CodePage,
|
2014-03-08 15:31:05 +00:00
|
|
|
IN BOOLEAN OutputCP);
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepSetCP */
|
2020-04-12 10:45:31 +00:00
|
|
|
CON_API(SrvSetConsoleCP,
|
|
|
|
CONSOLE_SETINPUTOUTPUTCP, SetConsoleCPRequest)
|
2010-05-31 06:28:55 +00:00
|
|
|
{
|
2012-11-18 13:10:03 +00:00
|
|
|
DPRINT("SrvSetConsoleCP, setting %s Code Page\n",
|
2014-03-08 15:31:05 +00:00
|
|
|
SetConsoleCPRequest->OutputCP ? "Output" : "Input");
|
2010-05-31 06:28:55 +00:00
|
|
|
|
2020-04-12 10:45:31 +00:00
|
|
|
return ConDrvSetConsoleCP((PCONSOLE)Console,
|
|
|
|
SetConsoleCPRequest->CodePage,
|
|
|
|
SetConsoleCPRequest->OutputCP);
|
2010-05-31 06:28:55 +00:00
|
|
|
}
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepGetProcessList */
|
2020-04-12 10:45:31 +00:00
|
|
|
CON_API(SrvGetConsoleProcessList,
|
|
|
|
CONSOLE_GETPROCESSLIST, GetProcessListRequest)
|
2010-05-31 06:28:55 +00:00
|
|
|
{
|
2012-11-18 13:10:03 +00:00
|
|
|
if (!CsrValidateMessageBuffer(ApiMessage,
|
2014-03-08 15:31:05 +00:00
|
|
|
(PVOID)&GetProcessListRequest->ProcessIdsList,
|
|
|
|
GetProcessListRequest->ProcessCount,
|
2012-11-18 13:10:03 +00:00
|
|
|
sizeof(DWORD)))
|
|
|
|
{
|
|
|
|
return STATUS_INVALID_PARAMETER;
|
|
|
|
}
|
|
|
|
|
2020-04-12 10:45:31 +00:00
|
|
|
return ConSrvGetConsoleProcessList(Console,
|
|
|
|
GetProcessListRequest->ProcessIdsList,
|
|
|
|
GetProcessListRequest->ProcessCount,
|
|
|
|
&GetProcessListRequest->ProcessCount);
|
2010-05-31 06:28:55 +00:00
|
|
|
}
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepGenerateCtrlEvent */
|
2020-04-12 10:45:31 +00:00
|
|
|
CON_API(SrvGenerateConsoleCtrlEvent,
|
|
|
|
CONSOLE_GENERATECTRLEVENT, GenerateCtrlEventRequest)
|
2010-05-31 06:28:55 +00:00
|
|
|
{
|
2020-04-12 10:45:31 +00:00
|
|
|
return ConSrvConsoleProcessCtrlEvent(Console,
|
|
|
|
GenerateCtrlEventRequest->ProcessGroupId,
|
|
|
|
GenerateCtrlEventRequest->CtrlEvent);
|
2010-05-31 06:28:55 +00:00
|
|
|
}
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepNotifyLastClose */
|
2020-04-12 10:45:31 +00:00
|
|
|
CON_API(SrvConsoleNotifyLastClose,
|
|
|
|
CONSOLE_NOTIFYLASTCLOSE, NotifyLastCloseRequest)
|
2013-08-30 17:53:45 +00:00
|
|
|
{
|
2014-04-21 01:22:17 +00:00
|
|
|
/* Only one process is allowed to be registered for last close notification */
|
2020-04-12 10:45:31 +00:00
|
|
|
if (Console->NotifyLastClose)
|
|
|
|
return STATUS_ACCESS_DENIED;
|
2014-04-21 01:22:17 +00:00
|
|
|
|
2020-04-12 10:45:31 +00:00
|
|
|
Console->NotifyLastClose = TRUE;
|
|
|
|
Console->NotifiedLastCloseProcess = ProcessData;
|
|
|
|
return STATUS_SUCCESS;
|
2013-08-30 17:53:45 +00:00
|
|
|
}
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepGetMouseInfo */
|
2020-04-12 10:45:31 +00:00
|
|
|
CON_API(SrvGetConsoleMouseInfo,
|
|
|
|
CONSOLE_GETMOUSEINFO, GetMouseInfoRequest)
|
2013-08-30 17:53:45 +00:00
|
|
|
{
|
2014-07-28 13:20:54 +00:00
|
|
|
/* Just retrieve the number of buttons of the mouse attached to this console */
|
|
|
|
GetMouseInfoRequest->NumButtons = GetSystemMetrics(SM_CMOUSEBUTTONS);
|
|
|
|
return STATUS_SUCCESS;
|
2013-08-30 17:53:45 +00:00
|
|
|
}
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepSetKeyShortcuts */
|
2013-08-30 17:53:45 +00:00
|
|
|
CSR_API(SrvSetConsoleKeyShortcuts)
|
|
|
|
{
|
|
|
|
DPRINT1("%s not yet implemented\n", __FUNCTION__);
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepGetKeyboardLayoutName */
|
2020-04-12 10:45:31 +00:00
|
|
|
CON_API(SrvGetConsoleKeyboardLayoutName,
|
|
|
|
CONSOLE_GETKBDLAYOUTNAME, GetKbdLayoutNameRequest)
|
2013-08-30 17:53:45 +00:00
|
|
|
{
|
2014-08-06 21:01:23 +00:00
|
|
|
/* Retrieve the keyboard layout name of the system */
|
|
|
|
if (GetKbdLayoutNameRequest->Ansi)
|
|
|
|
GetKeyboardLayoutNameA((PCHAR)GetKbdLayoutNameRequest->LayoutBuffer);
|
|
|
|
else
|
|
|
|
GetKeyboardLayoutNameW((PWCHAR)GetKbdLayoutNameRequest->LayoutBuffer);
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
2013-08-30 17:53:45 +00:00
|
|
|
}
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepCharType */
|
2013-08-30 17:53:45 +00:00
|
|
|
CSR_API(SrvGetConsoleCharType)
|
|
|
|
{
|
|
|
|
DPRINT1("%s not yet implemented\n", __FUNCTION__);
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepSetLocalEUDC */
|
2013-08-30 17:53:45 +00:00
|
|
|
CSR_API(SrvSetConsoleLocalEUDC)
|
|
|
|
{
|
|
|
|
DPRINT1("%s not yet implemented\n", __FUNCTION__);
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepSetCursorMode */
|
2013-08-30 17:53:45 +00:00
|
|
|
CSR_API(SrvSetConsoleCursorMode)
|
|
|
|
{
|
|
|
|
DPRINT1("%s not yet implemented\n", __FUNCTION__);
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepGetCursorMode */
|
2013-08-30 17:53:45 +00:00
|
|
|
CSR_API(SrvGetConsoleCursorMode)
|
|
|
|
{
|
|
|
|
DPRINT1("%s not yet implemented\n", __FUNCTION__);
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepGetNlsMode */
|
2013-08-30 17:53:45 +00:00
|
|
|
CSR_API(SrvGetConsoleNlsMode)
|
|
|
|
{
|
|
|
|
DPRINT1("%s not yet implemented\n", __FUNCTION__);
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepSetNlsMode */
|
2013-08-30 17:53:45 +00:00
|
|
|
CSR_API(SrvSetConsoleNlsMode)
|
|
|
|
{
|
|
|
|
DPRINT1("%s not yet implemented\n", __FUNCTION__);
|
|
|
|
return STATUS_NOT_IMPLEMENTED;
|
|
|
|
}
|
|
|
|
|
2019-12-31 00:21:42 +00:00
|
|
|
/* API_NUMBER: ConsolepGetLangId */
|
2022-01-14 21:00:55 +00:00
|
|
|
CON_API(SrvGetConsoleLangId,
|
|
|
|
CONSOLE_GETLANGID, LangIdRequest)
|
2013-08-30 17:53:45 +00:00
|
|
|
{
|
2022-01-14 21:00:55 +00:00
|
|
|
/*
|
|
|
|
* Quoting MS Terminal, see function GetConsoleLangId() at
|
|
|
|
* https://github.com/microsoft/terminal/blob/main/src/host/srvinit.cpp#L655
|
|
|
|
* "Only attempt to return the Lang ID if the Windows ACP on console
|
|
|
|
* launch was an East Asian Code Page."
|
|
|
|
*
|
|
|
|
* The underlying logic is as follows:
|
|
|
|
*
|
|
|
|
* - When the current user's UI language is *not* CJK, the user expects
|
|
|
|
* to not see any CJK output to the console by default, even if its
|
|
|
|
* output has been set to a CJK code page (this is possible when CJK
|
|
|
|
* fonts are installed on the system). That is, of course, unless if
|
|
|
|
* the attached console program chooses to actually output CJK text.
|
|
|
|
* Whatever current language of the running program's thread should
|
|
|
|
* be kept: STATUS_NOT_SUPPORTED is returned.
|
|
|
|
*
|
|
|
|
* - When the current user's UI language *is* CJK, the user expects to
|
|
|
|
* see CJK output to the console by default when its code page is CJK.
|
|
|
|
* A valid LangId is returned in this case to ensure this.
|
|
|
|
* However, if the console code page is not CJK, then it is evident
|
|
|
|
* that CJK text will not be able to be correctly shown, and therefore
|
|
|
|
* we should fall back to a standard language that can be shown, namely
|
|
|
|
* en-US english, instead of keeping the current language.
|
|
|
|
*/
|
|
|
|
|
|
|
|
BYTE UserCharSet = CodePageToCharSet(GetACP());
|
|
|
|
if (!IsCJKCharSet(UserCharSet))
|
|
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
|
|
|
|
/* Return a "best-suited" language ID corresponding
|
|
|
|
* to the active console output code page. */
|
|
|
|
switch (Console->OutputCodePage)
|
|
|
|
{
|
|
|
|
/** ReactOS-specific: do nothing if the code page is UTF-8. This will allow
|
|
|
|
** programs to naturally output in whatever current language they are. **/
|
|
|
|
case CP_UTF8:
|
|
|
|
return STATUS_NOT_SUPPORTED;
|
|
|
|
/** End ReactOS-specific **/
|
|
|
|
case CP_JAPANESE:
|
|
|
|
LangIdRequest->LangId = MAKELANGID(LANG_JAPANESE, SUBLANG_DEFAULT);
|
|
|
|
break;
|
|
|
|
case CP_KOREAN:
|
|
|
|
LangIdRequest->LangId = MAKELANGID(LANG_KOREAN, SUBLANG_KOREAN);
|
|
|
|
break;
|
|
|
|
case CP_CHINESE_SIMPLIFIED:
|
|
|
|
LangIdRequest->LangId = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_SIMPLIFIED);
|
|
|
|
break;
|
|
|
|
case CP_CHINESE_TRADITIONAL:
|
|
|
|
LangIdRequest->LangId = MAKELANGID(LANG_CHINESE, SUBLANG_CHINESE_TRADITIONAL);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
/* Default to en-US english otherwise */
|
|
|
|
LangIdRequest->LangId = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return STATUS_SUCCESS;
|
2013-08-30 17:53:45 +00:00
|
|
|
}
|
|
|
|
|
2010-05-31 06:28:55 +00:00
|
|
|
/* EOF */
|