diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/sm | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to 'private/sm')
26 files changed, 10312 insertions, 0 deletions
diff --git a/private/sm/client/makefile b/private/sm/client/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/sm/client/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/sm/client/smcsup.c b/private/sm/client/smcsup.c new file mode 100644 index 000000000..e2cc73230 --- /dev/null +++ b/private/sm/client/smcsup.c @@ -0,0 +1,125 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + smcsup.c + +Abstract: + + Session Manager Client Support APIs + +Author: + + Mark Lucovsky (markl) 05-Oct-1989 + +Revision History: + +--*/ + +#include "smdllp.h" +#include <string.h> + +NTSTATUS +SmConnectToSm( + IN PUNICODE_STRING SbApiPortName OPTIONAL, + IN HANDLE SbApiPort OPTIONAL, + IN ULONG SbImageType OPTIONAL, + OUT PHANDLE SmApiPort + ) + +/*++ + +Routine Description: + + This function is used to connect to the NT Session Manager + +Arguments: + + SbApiPortName - Supplies the name of the sub system's session management + API port (for Sb APIs). That the session manager is to connect with. + + SbApiPort - Supplies a port handle to the connection port where the + subsystem's session management (Sb) APIs are exported. + + SbImageType - Supplies the image type that the connecting subsystem + serves. + + SmApiPort - Returns the communication port which is connected to the + session manager and over which Sm APIs may be made. + +Return Value: + + TBD. + +--*/ + +{ + NTSTATUS st; + UNICODE_STRING PortName; + ULONG ConnectInfoLength; + PSBCONNECTINFO ConnectInfo; + SBAPIMSG Message; + SECURITY_QUALITY_OF_SERVICE DynamicQos; + + // + // Set up the security quality of service parameters to use over the + // port. Use the most efficient (least overhead) - which is dynamic + // rather than static tracking. + // + + DynamicQos.ImpersonationLevel = SecurityImpersonation; + DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; + DynamicQos.EffectiveOnly = TRUE; + + + RtlInitUnicodeString(&PortName,L"\\SmApiPort"); + ConnectInfoLength = sizeof(SBCONNECTINFO); + ConnectInfo = &Message.ConnectionRequest; + + // + // Subsystems must specify an SbApiPortName + // + + if ( ARGUMENT_PRESENT(SbApiPortName) ) { + + if ( !ARGUMENT_PRESENT(SbApiPort) ) { + return STATUS_INVALID_PARAMETER_MIX; + } + if ( !ARGUMENT_PRESENT(SbImageType) ) { + return STATUS_INVALID_PARAMETER_MIX; + } + + RtlMoveMemory( + ConnectInfo->EmulationSubSystemPortName, + SbApiPortName->Buffer, + SbApiPortName->Length + ); + ConnectInfo->EmulationSubSystemPortName[SbApiPortName->Length>>1] = UNICODE_NULL; + ConnectInfo->SubsystemImageType = SbImageType; + + } else { + ConnectInfo->EmulationSubSystemPortName[0] = UNICODE_NULL; + ConnectInfo->SubsystemImageType = 0; + } + + st = NtConnectPort( + SmApiPort, + &PortName, + &DynamicQos, + NULL, + NULL, + NULL, + ConnectInfo, + &ConnectInfoLength + ); + + if ( !NT_SUCCESS(st) ) { + KdPrint(("SmConnectToSm: Connect to Sm failed %lx\n",st)); + return st; + } + + return STATUS_SUCCESS; + +} diff --git a/private/sm/client/smdllp.h b/private/sm/client/smdllp.h new file mode 100644 index 000000000..cc57f060e --- /dev/null +++ b/private/sm/client/smdllp.h @@ -0,0 +1,30 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + smdllp.h + +Abstract: + + Session Manager Dll Private Types and Prototypes + +Author: + + Mark Lucovsky (markl) 04-Oct-1989 + +Revision History: + +--*/ + +#ifndef _SMSRVP_ +#define _SMSRVP_ + +#include <nt.h> +#include <ntrtl.h> +#include <ntsm.h> +#include <ntdbg.h> +#include "sm.h" + +#endif // _SMDLLP_ diff --git a/private/sm/client/smstub.c b/private/sm/client/smstub.c new file mode 100644 index 000000000..6bd47b4f6 --- /dev/null +++ b/private/sm/client/smstub.c @@ -0,0 +1,213 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + smstub.c + +Abstract: + + Session Manager Client Support APIs + +Author: + + Mark Lucovsky (markl) 05-Oct-1989 + +Revision History: + +--*/ + +#include "smdllp.h" +#include <string.h> + +NTSTATUS +SmExecPgm( + IN HANDLE SmApiPort, + IN PRTL_USER_PROCESS_INFORMATION ProcessInformation, + IN BOOLEAN DebugFlag + ) + +/*++ + +Routine Description: + + This routine allows a process to start a process using the + facilities provided by the NT Session manager. + + This function closes all handles passed to it. + +Arguments: + + SmApiPort - Supplies a handle to a communications port connected + to the Session Manager. + + ProcessInformation - Supplies a process description as returned + by RtlCreateUserProcess. + + DebugFlag - Supplies and optional parameter which if set indicates + that the caller wants to debug this process and act as its + debug user interface. + +Return Value: + + TBD. + +--*/ + +{ + NTSTATUS st; + + SMAPIMSG SmApiMsg; + PSMEXECPGM args; + + args = &SmApiMsg.u.ExecPgm; + + args->ProcessInformation = *ProcessInformation; + + args->DebugFlag = DebugFlag; + + SmApiMsg.ApiNumber = SmExecPgmApi; + SmApiMsg.h.u1.s1.DataLength = sizeof(*args) + 8; + SmApiMsg.h.u1.s1.TotalLength = sizeof(SmApiMsg); + SmApiMsg.h.u2.ZeroInit = 0L; + + st = NtRequestWaitReplyPort( + SmApiPort, + (PPORT_MESSAGE) &SmApiMsg, + (PPORT_MESSAGE) &SmApiMsg + ); + + if ( NT_SUCCESS(st) ) { + st = SmApiMsg.ReturnedStatus; + } else { + KdPrint(("SmExecPgm: NtRequestWaitReply Failed %lx\n",st)); + } + + NtClose(ProcessInformation->Process); + NtClose(ProcessInformation->Thread); + return st; + +} + +NTSTATUS +NTAPI +SmLoadDeferedSubsystem( + IN HANDLE SmApiPort, + IN PUNICODE_STRING DeferedSubsystem + ) + +/*++ + +Routine Description: + + This routine allows a process to start a defered subsystem. + +Arguments: + + SmApiPort - Supplies a handle to a communications port connected + to the Session Manager. + + DeferedSubsystem - Supplies the name of the defered subsystem to load. + +Return Value: + + TBD. + +--*/ + +{ + NTSTATUS st; + + SMAPIMSG SmApiMsg; + PSMLOADDEFERED args; + + if ( DeferedSubsystem->Length >> 1 > SMP_MAXIMUM_SUBSYSTEM_NAME ) { + return STATUS_INVALID_PARAMETER; + } + + args = &SmApiMsg.u.LoadDefered; + args->SubsystemNameLength = DeferedSubsystem->Length; + RtlCopyMemory(args->SubsystemName,DeferedSubsystem->Buffer,DeferedSubsystem->Length); + + SmApiMsg.ApiNumber = SmLoadDeferedSubsystemApi; + SmApiMsg.h.u1.s1.DataLength = sizeof(*args) + 8; + SmApiMsg.h.u1.s1.TotalLength = sizeof(SmApiMsg); + SmApiMsg.h.u2.ZeroInit = 0L; + + st = NtRequestWaitReplyPort( + SmApiPort, + (PPORT_MESSAGE) &SmApiMsg, + (PPORT_MESSAGE) &SmApiMsg + ); + + if ( NT_SUCCESS(st) ) { + st = SmApiMsg.ReturnedStatus; + } else { + KdPrint(("SmExecPgm: NtRequestWaitReply Failed %lx\n",st)); + } + + return st; + +} + + +NTSTATUS +SmSessionComplete( + IN HANDLE SmApiPort, + IN ULONG SessionId, + IN NTSTATUS CompletionStatus + ) + +/*++ + +Routine Description: + + This routine is used to report completion of a session to + the NT Session manager. + +Arguments: + + SmApiPort - Supplies a handle to a communications port connected + to the Session Manager. + + SessionId - Supplies the session id of the session which is now completed. + + CompletionStatus - Supplies the completion status of the session. + +Return Value: + + TBD. + +--*/ + +{ + NTSTATUS st; + + SMAPIMSG SmApiMsg; + PSMSESSIONCOMPLETE args; + + args = &SmApiMsg.u.SessionComplete; + + args->SessionId = SessionId; + args->CompletionStatus = CompletionStatus; + + SmApiMsg.ApiNumber = SmSessionCompleteApi; + SmApiMsg.h.u1.s1.DataLength = sizeof(*args) + 8; + SmApiMsg.h.u1.s1.TotalLength = sizeof(SmApiMsg); + SmApiMsg.h.u2.ZeroInit = 0L; + + st = NtRequestWaitReplyPort( + SmApiPort, + (PPORT_MESSAGE) &SmApiMsg, + (PPORT_MESSAGE) &SmApiMsg + ); + + if ( NT_SUCCESS(st) ) { + st = SmApiMsg.ReturnedStatus; + } else { + KdPrint(("SmCompleteSession: NtRequestWaitReply Failed %lx\n",st)); + } + + return st; +} diff --git a/private/sm/client/sources b/private/sm/client/sources new file mode 100644 index 000000000..8ec140ddf --- /dev/null +++ b/private/sm/client/sources @@ -0,0 +1,35 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 12-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=sm +MINORCOMP=client + +TARGETNAME=smdll +TARGETPATH=\nt\public\sdk\lib +TARGETTYPE=LIBRARY + +INCLUDES=..\inc + +SOURCES=smcsup.c\ + smstub.c diff --git a/private/sm/dirs b/private/sm/dirs new file mode 100644 index 000000000..589b0d982 --- /dev/null +++ b/private/sm/dirs @@ -0,0 +1,26 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dirs. + +Abstract: + + This file specifies the subdirectories of the current directory that + contain component makefiles. + + +Author: + + Steve Wood (stevewo) 17-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\dirs.tpl + +!ENDIF + +DIRS=server \ + client + +OPTIONAL_DIRS= diff --git a/private/sm/inc/sm.h b/private/sm/inc/sm.h new file mode 100644 index 000000000..043699cdc --- /dev/null +++ b/private/sm/inc/sm.h @@ -0,0 +1,94 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sm.h + +Abstract: + + Session Manager Types and Prototypes + +Author: + + Mark Lucovsky (markl) 04-Oct-1989 + +Revision History: + +--*/ + +#ifndef _SM_ +#define _SM_ + + + + +// +// Message formats used by clients of the session manager. +// + +typedef struct _SMCONNECTINFO { + ULONG ImageType; +} SMCONNECTINFO, *PSMCONNECTINFO; + +typedef enum _SMAPINUMBER { + SmCreateForeignSessionApi, + SmSessionCompleteApi, + SmTerminateForeignSessionApi, + SmExecPgmApi, + SmLoadDeferedSubsystemApi, + SmMaxApiNumber +} SMAPINUMBER; + +typedef struct _SMCREATEFOREIGNSESSION { + ULONG ForeignSessionId; + ULONG SourceSessionId; + RTL_USER_PROCESS_INFORMATION ProcessInformation; + CLIENT_ID DebugUiClientId; +} SMCREATEFOREIGNSESSION, *PSMCREATEFOREIGNSESSION; + +typedef struct _SMSESSIONCOMPLETE { + ULONG SessionId; + NTSTATUS CompletionStatus; +} SMSESSIONCOMPLETE, *PSMSESSIONCOMPLETE; + +typedef struct _SMTERMINATEFOREIGNSESSION { + ULONG Tbd; +} SMTERMINATEFOREIGNSESSION, *PSMTERMINATEFOREIGNSESSION; + + + +typedef struct _SMEXECPGM { + RTL_USER_PROCESS_INFORMATION ProcessInformation; + BOOLEAN DebugFlag; +} SMEXECPGM, *PSMEXECPGM; + +#define SMP_MAXIMUM_SUBSYSTEM_NAME 32 + +typedef struct _SMLOADDEFERED { + ULONG SubsystemNameLength; + WCHAR SubsystemName[SMP_MAXIMUM_SUBSYSTEM_NAME]; +} SMLOADDEFERED, *PSMLOADDEFERED; + +typedef struct _SMAPIMSG { + PORT_MESSAGE h; + SMAPINUMBER ApiNumber; + NTSTATUS ReturnedStatus; + union { + SMCREATEFOREIGNSESSION CreateForeignSession; + SMSESSIONCOMPLETE SessionComplete; + SMTERMINATEFOREIGNSESSION TerminateForeignComplete; + SMEXECPGM ExecPgm; + SMLOADDEFERED LoadDefered; + } u; +} SMAPIMSG, *PSMAPIMSG; + +typedef union _SMMESSAGE_SIZE { + DBGKM_APIMSG m1; + SMAPIMSG m2; + SBAPIMSG m3; +} SMMESSAGE_SIZE; + + +#endif // _SM_ diff --git a/private/sm/server/dbgapsup.c b/private/sm/server/dbgapsup.c new file mode 100644 index 000000000..6233b8a9b --- /dev/null +++ b/private/sm/server/dbgapsup.c @@ -0,0 +1,236 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dbgapsup.c + +Abstract: + + This module implements support routines for application threads + +Author: + + Mark Lucovsky (markl) 23-Jan-1990 + +Revision History: + +--*/ + +#include "smsrvp.h" + +PDBGP_APP_THREAD +DbgpIsAppInHashTable( + IN PCLIENT_ID AppClientId + ) + +/*++ + +Routine Description: + + This routine scans the application thread hash table looking + for an application thread that matches the specified client id. + + If a matching application thread is found, then its address is + returned. + +Arguments: + + AppClientId - Supplies the address of ClientId of the application + thread to locate. + +Return Value: + + NULL - No application thread with a matching ClientId could be located. + + NON-NULL - Returns the address of the application thread that + matches the specified ClientId. + +--*/ + +{ + ULONG Index; + PLIST_ENTRY Head, Next; + PDBGP_APP_THREAD AppThread; + + RtlEnterCriticalSection(&DbgpHashTableLock); + + Index = DBGP_THREAD_CLIENT_ID_TO_INDEX(AppClientId); + + Head = &DbgpAppThreadHashTable[Index]; + Next = Head->Flink; + + while ( Next != Head ) { + AppThread = CONTAINING_RECORD(Next,DBGP_APP_THREAD,HashTableLinks); + if ( DBGP_CLIENT_IDS_EQUAL( + &AppThread->AppClientId, + AppClientId + )) { + RtlLeaveCriticalSection(&DbgpHashTableLock); +//DbgpDumpAppThread(AppThread); + return AppThread; + } + Next = Next->Flink; + } + + RtlLeaveCriticalSection(&DbgpHashTableLock); +#if DBG +// DbgPrint("DBGSS: AppThread for %lx.%lx Not Found\n",AppClientId->UniqueProcess,AppClientId->UniqueThread); +#endif // DBG + return NULL; +} + +PDBGP_APP_PROCESS +DbgpIsAppProcessInHashTable( + IN PCLIENT_ID AppClientId + ) + +/*++ + +Routine Description: + + This routine scans the application process hash table looking for an + application process whose ClientId.UniqueOrocess field matches the + specified client id's. + + If a matching application process is found, then its address is + returned. + +Arguments: + + AppClientId - Supplies the address of ClientId of the application + process to locate. + +Return Value: + + NULL - No application process with a matching ClientId could be located. + + NON-NULL - Returns the address of the application process that + matches the specified ClientId. + +--*/ + +{ + ULONG Index; + PLIST_ENTRY Head, Next; + PDBGP_APP_PROCESS AppProcess; + + RtlEnterCriticalSection(&DbgpHashTableLock); + + Index = DBGP_PROCESS_CLIENT_ID_TO_INDEX(AppClientId); + + Head = &DbgpAppProcessHashTable[Index]; + Next = Head->Flink; + + while ( Next != Head ) { + AppProcess = CONTAINING_RECORD(Next,DBGP_APP_PROCESS,HashTableLinks); + if ( AppProcess->AppClientId.UniqueProcess == AppClientId->UniqueProcess) { + RtlLeaveCriticalSection(&DbgpHashTableLock); + return AppProcess; + } + Next = Next->Flink; + } + + RtlLeaveCriticalSection(&DbgpHashTableLock); +#if DBG +// DbgPrint("DBGSS: AppProcess for %lx.%lx Not Found\n",AppClientId->UniqueProcess,AppClientId->UniqueThread); +#endif // DBG + return NULL; +} + +PDBGP_APP_THREAD +DbgpLocateStateChangeApp( + IN PDBGP_USER_INTERFACE UserInterface, + OUT PDBG_STATE PreviousState + ) + +/*++ + +Routine Description: + + This routine scans the specified user interface's application list + looking for an application whose state has changed. If an + application whose State is not DbgIdle or DbgReplyPending is found, + its address is returned. + +Arguments: + + UserInterface - Supplies the address of UserInterface whose + application list is to be scanned. + + PreviousState - Supplies the address of a variable that returns + the previous debug state of an application thread reporting + a state change. + +Return Value: + + NULL - No application thread reporting a state change could be located. + + NON-NULL - Returns the address of the application thread reporting a state + change. + +--*/ + +{ + PLIST_ENTRY HeadProcess, NextProcess; + PLIST_ENTRY HeadThread, NextThread; + PDBGP_APP_THREAD AppThread; + PDBGP_APP_PROCESS AppProcess; + + RtlEnterCriticalSection(&UserInterface->UserInterfaceLock); + + HeadProcess = &UserInterface->AppProcessListHead; + NextProcess = HeadProcess->Flink; + + while ( NextProcess != HeadProcess ) { + + // + // For each process managed by the user interface, + // scan its thread list + // + + AppProcess = CONTAINING_RECORD(NextProcess,DBGP_APP_PROCESS,AppLinks); + + HeadThread = &AppProcess->AppThreadListHead; + NextThread = HeadThread->Flink; + + while ( NextThread != HeadThread ) { + AppThread = CONTAINING_RECORD(NextThread,DBGP_APP_THREAD,AppLinks); + if ( DBGP_REPORTING_STATE_CHANGE(AppThread) ) { + *PreviousState = AppThread->CurrentState; + AppThread->ContinueState = AppThread->CurrentState; + AppThread->CurrentState = DbgReplyPending; + + // + // Reshuffle so that this thread is placed + // at front of list for process, and so that + // process is placed at front of list for + // user interface + // + + RemoveEntryList(&AppThread->AppLinks); + InsertHeadList( + &AppProcess->AppThreadListHead, + &AppThread->AppLinks + ); + + RemoveEntryList(&AppProcess->AppLinks); + InsertHeadList( + &UserInterface->AppProcessListHead, + &AppProcess->AppLinks + ); + + RtlLeaveCriticalSection(&UserInterface->UserInterfaceLock); +//DbgpDumpAppThread(AppThread); + return AppThread; + } + NextThread = NextThread->Flink; + } + + NextProcess = NextProcess->Flink; + } + + RtlLeaveCriticalSection(&UserInterface->UserInterfaceLock); + return NULL; +} diff --git a/private/sm/server/dbgdump.c b/private/sm/server/dbgdump.c new file mode 100644 index 000000000..2da817030 --- /dev/null +++ b/private/sm/server/dbgdump.c @@ -0,0 +1,80 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dbgdump.c + +Abstract: + + Dump routines for Debug Subsystem + +Author: + + Mark Lucovsky (markl) 23-Jan-1990 + +Revision History: + +--*/ + +#if DBG + +#include "smsrvp.h" + +VOID +DbgpDumpUserInterface ( + IN PDBGP_USER_INTERFACE UserInterface + ) +{ + + DbgPrint("DMP_UI: UserInterface at 0x%lx\n",UserInterface); + DbgPrint("DMP_UI: ClientId %lx.%lx\n", + UserInterface->DebugUiClientId.UniqueProcess, + UserInterface->DebugUiClientId.UniqueThread + ); +} + +VOID +DbgpDumpAppThread ( + IN PDBGP_APP_THREAD AppThread + ) +{ + + DbgPrint("DMP_AT: AppThread at 0x%lx\n",AppThread); + DbgPrint("DMP_AT: AppClientId %lx.%lx\n", + AppThread->AppClientId.UniqueProcess, + AppThread->AppClientId.UniqueThread + ); + DbgPrint("DMP_AT: CurrentState %lx ContinueState %lx\n", + AppThread->CurrentState, + AppThread->ContinueState + ); + DbgPrint("DMP_AT: AppProcess %lx\n", + AppThread->AppProcess + ); + DbgPrint("DMP_AT: UserInterface %lx\n", + AppThread->UserInterface + ); + DbgPrint("DMP_AT: HandleToThread %lx\n", + AppThread->HandleToThread + ); + DbgPrint("DMP_AT: Subsystem %lx\n", + AppThread->Subsystem + ); +} + +VOID +DbgpDumpSubsystem ( + IN PDBGP_SUBSYSTEM Subsystem + ) +{ + + DbgPrint("DMP_SS: Subsystem at 0x%lx\n",Subsystem); + DbgPrint("DMP_SS: ClientId %lx.%lx\n", + Subsystem->SubsystemClientId.UniqueProcess, + Subsystem->SubsystemClientId.UniqueThread + ); +} + +#endif // DBG diff --git a/private/sm/server/dbginit.c b/private/sm/server/dbginit.c new file mode 100644 index 000000000..4043dad27 --- /dev/null +++ b/private/sm/server/dbginit.c @@ -0,0 +1,165 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dbginit.c + +Abstract: + + Debug Subsystem Initialization + +Author: + + Mark Lucovsky (markl) 22-Jan-1990 + +Revision History: + +--*/ + +#include "smsrvp.h" + +static SID_IDENTIFIER_AUTHORITY WorldSidAuthority = SECURITY_WORLD_SID_AUTHORITY; + +NTSTATUS +DbgpInit() +{ + + NTSTATUS st; + ANSI_STRING Name; + UNICODE_STRING UnicodeName; + OBJECT_ATTRIBUTES ObjA; + ULONG i; + ULONG Length; + PSID SeWorldSid; + PSECURITY_DESCRIPTOR SecurityDescriptor; + PACL Dacl; + + // + // Initialize the application thread hash table + // + + RtlInitializeCriticalSection(&DbgpHashTableLock); + for( i=0;i<DBGP_CLIENT_ID_HASHSIZE;i++) { + InitializeListHead(&DbgpAppThreadHashTable[i]); + InitializeListHead(&DbgpAppProcessHashTable[i]); + InitializeListHead(&DbgpUiHashTable[i]); + } + + + // + // create a security descriptor that allows all access + // + + SeWorldSid = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( DBG_TAG ), RtlLengthRequiredSid( 1 ) ); + RtlInitializeSid( SeWorldSid, &WorldSidAuthority, 1 ); + *(RtlSubAuthoritySid( SeWorldSid, 0 )) = SECURITY_WORLD_RID; + + Length = SECURITY_DESCRIPTOR_MIN_LENGTH + + (ULONG)sizeof(ACL) + + (ULONG)sizeof(ACCESS_ALLOWED_ACE) + + RtlLengthSid( SeWorldSid ); + + SecurityDescriptor = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( DBG_TAG ), Length); + ASSERT( SecurityDescriptor != NULL ); + + RtlCreateSecurityDescriptor(SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION); + + Dacl = (PACL)((PCHAR)SecurityDescriptor + SECURITY_DESCRIPTOR_MIN_LENGTH); + + RtlCreateAcl( Dacl, Length - SECURITY_DESCRIPTOR_MIN_LENGTH, ACL_REVISION2); + + RtlAddAccessAllowedAce ( + Dacl, + ACL_REVISION2, + PORT_ALL_ACCESS, + SeWorldSid + ); + RtlSetDaclSecurityDescriptor ( + SecurityDescriptor, + TRUE, + Dacl, + FALSE + ); + + // + // Create ports for Subsystems to connect to and for + // user interfaces to connect to + // + + RtlInitAnsiString( &Name, "\\DbgSsApiPort" ); + st = RtlAnsiStringToUnicodeString( &UnicodeName, &Name, TRUE); + ASSERT(NT_SUCCESS(st)); + InitializeObjectAttributes( &ObjA, &UnicodeName, 0, NULL, + SecurityDescriptor ); + + st = NtCreatePort( + &DbgpSsApiPort, + &ObjA, + 0, + sizeof(DBGSS_APIMSG), + sizeof(DBGSS_APIMSG) * 32 + ); + RtlFreeUnicodeString(&UnicodeName); + ASSERT( NT_SUCCESS(st) ); + + + RtlInitAnsiString( &Name, "\\DbgUiApiPort" ); + + st = RtlAnsiStringToUnicodeString( &UnicodeName, &Name, TRUE); + ASSERT(NT_SUCCESS(st)); + InitializeObjectAttributes( &ObjA, &UnicodeName, 0, NULL, + SecurityDescriptor ); + + st = NtCreatePort( + &DbgpUiApiPort, + &ObjA, + sizeof(HANDLE), + sizeof(DBGUI_APIMSG), + sizeof(DBGUI_APIMSG) * 32 + ); + RtlFreeUnicodeString(&UnicodeName); + ASSERT( NT_SUCCESS(st) ); + + // + // Clean up security stuff + // + + RtlFreeHeap( RtlProcessHeap(), 0, SeWorldSid ); + RtlFreeHeap( RtlProcessHeap(), 0, SecurityDescriptor ); + + // + // Create Initial Set of Server Threads + // + + st = RtlCreateUserThread( + NtCurrentProcess(), + NULL, + FALSE, + 0L, + 0L, + 0L, + DbgpUiApiLoop, + NULL, + NULL, + NULL + ); + ASSERT( NT_SUCCESS(st) ); + + st = RtlCreateUserThread( + NtCurrentProcess(), + NULL, + FALSE, + 0L, + 0L, + 0L, + DbgpSsApiLoop, + NULL, + NULL, + NULL + ); + ASSERT( NT_SUCCESS(st) ); + + return STATUS_SUCCESS; +} diff --git a/private/sm/server/dbgloop.c b/private/sm/server/dbgloop.c new file mode 100644 index 000000000..c2b8faa18 --- /dev/null +++ b/private/sm/server/dbgloop.c @@ -0,0 +1,560 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dbgloop.c + +Abstract: + + Debug Subsystem Listen and API loops + +Author: + + Mark Lucovsky (markl) 04-Oct-1989 + +Revision History: + +--*/ + +#include "smsrvp.h" + +NTSTATUS +DbgpSsHandleConnectionRequest( + IN PPORT_MESSAGE ConnectionRequest + ); + +NTSTATUS +DbgpUiHandleConnectionRequest( + IN PDBGUI_APIMSG Message + ); + + +PDBGSS_API DbgpSsDispatch[DbgSsMaxApiNumber] = { + DbgpSsException, + DbgpSsCreateThread, + DbgpSsCreateProcess, + DbgpSsExitThread, + DbgpSsExitProcess, + DbgpSsLoadDll, + DbgpSsUnloadDll + }; + + +#if DBG +PSZ DbgpSsApiName[ DbgSsMaxApiNumber+1 ] = { + "DbgpSsException", + "DbgpSsCreateThread", + "DbgpSsCreateProcess", + "DbgpSsExitThread", + "DbgpSsExitProcess", + "DbgpSsLoadDll", + "DbgpSsUnloadDll", + "Unknown DbgSs Api Number" +}; +#endif // DBG + +EXCEPTION_DISPOSITION +DbgpUnhandledExceptionFilter( + struct _EXCEPTION_POINTERS *ExceptionInfo + ) +{ + + UNICODE_STRING UnicodeParameter; + ULONG Parameters[ 4 ]; + ULONG Response; + BOOLEAN WasEnabled; + NTSTATUS Status; + + // + // Terminating will cause sm's wait to sense that we crashed. This will + // result in a clean shutdown due to sm's hard error logic + // + + // + // We are hosed, so raise a fata system error to shutdown the system. + // (Basically a user mode KeBugCheck). + // + + Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE, + (BOOLEAN)TRUE, + TRUE, + &WasEnabled + ); + + if (Status == STATUS_NO_TOKEN) { + + // + // No thread token, use the process token + // + + Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE, + (BOOLEAN)TRUE, + FALSE, + &WasEnabled + ); + } + + RtlInitUnicodeString( &UnicodeParameter, L"Session Manager" ); + Parameters[ 0 ] = (ULONG)&UnicodeParameter; + Parameters[ 1 ] = (ULONG)ExceptionInfo->ExceptionRecord->ExceptionCode; + Parameters[ 2 ] = (ULONG)ExceptionInfo->ExceptionRecord->ExceptionAddress; + Parameters[ 3 ] = (ULONG)ExceptionInfo->ContextRecord; + Status = NtRaiseHardError( STATUS_SYSTEM_PROCESS_TERMINATED, + 4, + 1, + Parameters, + OptionShutdownSystem, + &Response + ); + + // + // If this returns, giveup + // + + NtTerminateProcess(NtCurrentProcess(),ExceptionInfo->ExceptionRecord->ExceptionCode); + + return EXCEPTION_EXECUTE_HANDLER; +} + + +NTSTATUS +DbgpSsApiLoop ( + IN PVOID ThreadParameter + ) + +/*++ + +Routine Description: + + This is the API loop for DbgSs APIs. + +Arguments: + + ThreadParameter - Not Used. + +Return Value: + + None. + +--*/ + +{ + DBGSRV_APIMSG ContinueMsg; + DBGSS_APIMSG ApiMsg; + NTSTATUS Status; + PDBGP_SUBSYSTEM Subsystem; + + try { + for(;;) { + + Status = NtReplyWaitReceivePort( + DbgpSsApiPort, + (PVOID *) &Subsystem, + NULL, + (PPORT_MESSAGE) &ApiMsg + ); + ASSERT( NT_SUCCESS(Status) ); + + if (ApiMsg.h.u2.s2.Type == LPC_CONNECTION_REQUEST) { + DbgpSsHandleConnectionRequest( (PPORT_MESSAGE) &ApiMsg ); + } else if (ApiMsg.h.u2.s2.Type == LPC_PORT_CLOSED ) { + ; + } else { + + ApiMsg.ReturnedStatus = STATUS_PENDING; + + if (ApiMsg.ApiNumber >= DbgSsMaxApiNumber ) { + + Status = STATUS_NOT_IMPLEMENTED; + + } else { + + Status = (DbgpSsDispatch[ApiMsg.ApiNumber])(Subsystem,&ApiMsg); + } + + // + // Since all DbgSs API's are asynchronous, DBG_REPLY_LATER is used + // as a status code that means the API has been started. A continue + // will arrive at some point in the future. Otherwise, this loop + // will actually to the continue. + // + + if ( Status != DBG_REPLY_LATER ) { + + KdPrint(("DBGSS: %s Api Request Failed %lx\n", + DbgpSsApiName[ ApiMsg.ApiNumber ], + Status + )); + + DBGSRV_FORMAT_API_MSG(ContinueMsg,DbgSrvContinueApi,0L,ApiMsg.ContinueKey); + ContinueMsg.ReturnedStatus = Status; + + Status = NtRequestPort(Subsystem->CommunicationPort, (PPORT_MESSAGE)&ContinueMsg); + KdPrint(("DBGSS: Request Status %x\n",Status)); + } + } + } + } except (DbgpUnhandledExceptionFilter( GetExceptionInformation() )) { + ; + } + + // + // Make the compiler happy + // + + return STATUS_UNSUCCESSFUL; +} + +NTSTATUS +DbgpSsHandleConnectionRequest( + IN PPORT_MESSAGE ConnectionRequest + ) +{ + NTSTATUS st; + HANDLE CommunicationPort; + HANDLE SubsystemProcessHandle; + OBJECT_ATTRIBUTES Obja; + PDBGP_SUBSYSTEM Subsystem; + BOOLEAN Accept; + + InitializeObjectAttributes(&Obja, NULL, 0, NULL, NULL); + st = NtOpenProcess( + &SubsystemProcessHandle, + DBGP_OPEN_SUBSYSTEM_ACCESS, + &Obja, + &ConnectionRequest->ClientId + ); + + // + // If we are unable to open the process, then we can not complete + // connection. This is because the handle is needed to pass thread + // and process handles from the subsystem to the DebugUi. + // + + if ( !NT_SUCCESS(st) ) { + Accept = FALSE; + } else { + + Accept = TRUE; + + // + // Allocate a subsystem control block. + // The address of this block is used as the + // port context in all calls from a subsystem. + // + + Subsystem = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( DBG_TAG ), sizeof(DBGP_SUBSYSTEM)); + Subsystem->SubsystemProcessHandle = SubsystemProcessHandle; + Subsystem->SubsystemClientId = ConnectionRequest->ClientId; + } + + st = NtAcceptConnectPort( + &CommunicationPort, + (PVOID)Subsystem, + ConnectionRequest, + Accept, + NULL, + NULL + ); + ASSERT( NT_SUCCESS(st) ); + + if ( Accept ) { + + Subsystem->CommunicationPort = CommunicationPort; + st = NtCompleteConnectPort(CommunicationPort); + ASSERT( NT_SUCCESS(st) ); + } + + return st; +} + +PDBGUI_API DbgpUiDispatch[DbgUiMaxApiNumber] = { + DbgpUiWaitStateChange, + DbgpUiContinue + }; + + +#if DBG +PSZ DbgpUiApiName[ DbgUiMaxApiNumber+1 ] = { + "DbgpUiWaitStateChange", + "DbgpUiContinue", + "Unknown DbgUi Api Number" +}; +#endif // DBG + +NTSTATUS +DbgpUiApiLoop ( + IN PVOID ThreadParameter + ) + +/*++ + +Routine Description: + + This is the API loop for DbgUi APIs. + +Arguments: + + ThreadParameter - Not Used. + +Return Value: + + None. + +--*/ + +{ + PDBGUI_APIMSG ReplyMsg; + DBGUI_APIMSG ApiMsg; + NTSTATUS Status; + PDBGP_USER_INTERFACE UserInterface; + + try { + ReplyMsg = NULL; + for(;;) { + Status = NtReplyWaitReceivePort( + DbgpUiApiPort, + (PVOID *) &UserInterface, + (PPORT_MESSAGE) ReplyMsg, + (PPORT_MESSAGE) &ApiMsg + ); + if ( !NT_SUCCESS(Status) ) { + ReplyMsg = NULL; + continue; + } + + if (ApiMsg.h.u2.s2.Type == LPC_CONNECTION_REQUEST) { + DbgpUiHandleConnectionRequest( &ApiMsg ); + ReplyMsg = NULL; + continue; + } + + if (ApiMsg.h.u2.s2.Type == LPC_CLIENT_DIED) { + DbgpUiHasTerminated(&ApiMsg.h.ClientId); + ReplyMsg = NULL; + continue; + } + + if (ApiMsg.h.u2.s2.Type == LPC_PORT_CLOSED) { + ReplyMsg = NULL; + continue; + } + + ApiMsg.ReturnedStatus = STATUS_PENDING; + +#if DBG && 0 + if (ApiMsg.ApiNumber >= DbgUiMaxApiNumber ) { + ApiMsg.ApiNumber = DbgUiMaxApiNumber; + } + DbgPrint( "DBG_UILOOP: %s Api Request received from %lx.%lx\n", + DbgpUiApiName[ ApiMsg.ApiNumber ], + ApiMsg.h.ClientId.UniqueProcess, + ApiMsg.h.ClientId.UniqueThread + ); +#endif // DBG + + if (ApiMsg.ApiNumber >= DbgUiMaxApiNumber ) { + + Status = STATUS_NOT_IMPLEMENTED; + + } else { + + Status = (DbgpUiDispatch[ApiMsg.ApiNumber])(UserInterface,&ApiMsg); + } + + // + // Some APIs do not cause an immediate reply. This is signaled + // by returning DBG_REPLY_LATER + // + + if ( Status == DBG_REPLY_LATER ) { + ReplyMsg = NULL; + } else { + ApiMsg.ReturnedStatus = Status; + ReplyMsg = &ApiMsg; + } + + ApiMsg.ReturnedStatus = Status; + ReplyMsg = &ApiMsg; + } + } except (DbgpUnhandledExceptionFilter( GetExceptionInformation() )) { + ; + } + + // + // Make the compiler happy + // + + return STATUS_UNSUCCESSFUL; +} + + +NTSTATUS +DbgpUiHandleConnectionRequest( + IN PDBGUI_APIMSG Message + ) +{ + + NTSTATUS st; + HANDLE CommunicationPort; + HANDLE UserInterfaceHandle; + OBJECT_ATTRIBUTES Obja; + PDBGP_USER_INTERFACE UserInterface; + PHANDLE ConnectionInformation; + BOOLEAN Accept; + + // + // Createing a connection between a DebugUi and the debug + // subsystem causes the following to occur. + // + // - A UserInterface Control Block (UICB) is created and initialized + // - A handle to the Ui process is created and stored in UICB + // - A state change semaphore is created. A handle to this semaphore + // is placed in the Ui process. This handle is given SYNCHRONIZE + // access. The value of this handle is returned during connection + // accept as ConnectionInformation. + // - Address of the UICB is used as port context and is made available + // in all calls from the Ui. + // - The UICB is linked into the DebugUiHashTable + // + + InitializeObjectAttributes(&Obja, NULL, 0, NULL, NULL); + st = NtOpenProcess( + &UserInterfaceHandle, + DBGP_OPEN_UI_ACCESS, + &Obja, + &Message->h.ClientId + ); + + // + // If we are unable to open the process, then we can not complete + // connection. This is because the handle is needed to pass thread + // and process handles from the subsystem to the DebugUi. + // + + if ( !NT_SUCCESS(st) ) { + Accept = FALSE; + } else { + Accept = TRUE; + ConnectionInformation = &Message->DbgStateChangeSemaphore; + + // + // Allocate a DebugUserInterface control block. + // The address of this block is used as the + // port context in all calls from a DebugUi. + // + + UserInterface = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( DBG_TAG ), sizeof(DBGP_USER_INTERFACE)); + if ( !UserInterface ) { + st = STATUS_NO_MEMORY; + } else { + + // + // Initialize UserInterface Control Block + // + + UserInterface->DebugUiClientId = Message->h.ClientId; + UserInterface->DebugUiProcess = UserInterfaceHandle; + InitializeListHead(&UserInterface->AppProcessListHead); + + // + // Create a state change semaphore. Dbg gets all access to + // semaphore. A handle to this semaphore with SYNCHRONIZE + // access is duplicated into the Ui. This handle is used + // by Ui to wait for state changes. + // + + st = NtCreateSemaphore( + &UserInterface->StateChangeSemaphore, + SEMAPHORE_ALL_ACCESS, + NULL, + 0L, + MAXLONG + ); + } + if ( !NT_SUCCESS(st) ) { + + // + // Create semaphore failed, so don't accept connection + // + + NtClose(UserInterfaceHandle); + if ( UserInterface ) { + RtlFreeHeap(RtlProcessHeap(), 0,UserInterface); + } + Accept = FALSE; + } else { + + // + // Allocate a critical section for the user interface control + // block + // + + st = RtlInitializeCriticalSection( + &UserInterface->UserInterfaceLock + ); + + if ( !NT_SUCCESS(st) ) { + + NtClose(UserInterface->StateChangeSemaphore); + NtClose(UserInterfaceHandle); + RtlFreeHeap(RtlProcessHeap(), 0,UserInterface); + Accept = FALSE; + + } else { + + // + // If this operation is successful then connection request + // can be accepted. The Ui's handle to the state change + // semaphore is returned in the connection information + // structure. + // + + st = NtDuplicateObject( + NtCurrentProcess(), + UserInterface->StateChangeSemaphore, + UserInterfaceHandle, + ConnectionInformation, + SYNCHRONIZE, + 0L, + 0L + ); + + if ( !NT_SUCCESS(st) ) { + RtlDeleteCriticalSection( + &UserInterface->UserInterfaceLock + ); + NtClose(UserInterface->StateChangeSemaphore); + NtClose(UserInterfaceHandle); + RtlFreeHeap(RtlProcessHeap(), 0,UserInterface); + Accept = FALSE; + } else { + RtlEnterCriticalSection(&DbgpHashTableLock); + InsertTailList( + &DbgpUiHashTable[DBGP_PROCESS_CLIENT_ID_TO_INDEX(&UserInterface->DebugUiClientId)], + &UserInterface->HashTableLinks + ); + RtlLeaveCriticalSection(&DbgpHashTableLock); + } + } + } + } + + st = NtAcceptConnectPort( + &CommunicationPort, + (PVOID)UserInterface, + (PPORT_MESSAGE)Message, + Accept, + NULL, + NULL + ); + + if ( NT_SUCCESS(st) && Accept ) { + UserInterface->CommunicationPort = CommunicationPort; + NtCompleteConnectPort(CommunicationPort); + } + + return st; +} diff --git a/private/sm/server/dbgsrvp.h b/private/sm/server/dbgsrvp.h new file mode 100644 index 000000000..97a32d2f6 --- /dev/null +++ b/private/sm/server/dbgsrvp.h @@ -0,0 +1,338 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dbgsrvp.h + +Abstract: + + Debug Subsystem Private Types and Prototypes + +Author: + + Mark Lucovsky (markl) 23-Jan-1990 + +Revision History: + +--*/ + +#ifndef _DBGSRVP_ +#define _DBGSRVP_ + +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <ntsm.h> +#include <ntdbg.h> + +// +// Constants +// + +// +// When a subsystem connects, its process is opened. This allows us +// to duplicate objects into and out of the subsystem. +// + +#define DBGP_OPEN_SUBSYSTEM_ACCESS (PROCESS_DUP_HANDLE | READ_CONTROL) + +// +// When a user interface connects, its process is opened. This allows us +// to duplicate objects into and out of the user interface. +// + +#define DBGP_OPEN_UI_ACCESS (PROCESS_DUP_HANDLE | READ_CONTROL) + +// +// When an application thread is made known to Dbg, it is opened with the +// following access. Once the thread is picked up (through +// DbgUiWaitStateChange), the handle is duplicated into its user +// interface and the local handle is closed. +// + +#define DBGP_OPEN_APP_THREAD_ACCESS \ + (THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME | \ + THREAD_QUERY_INFORMATION | READ_CONTROL | THREAD_TERMINATE) + +#define DBGP_DUP_APP_THREAD_ACCESS \ + (THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME | \ + THREAD_QUERY_INFORMATION | READ_CONTROL | THREAD_TERMINATE) +// +// When an application process is made known to Dbg, it is opened with the +// following access. Once the process is picked up (through +// DbgUiWaitStateChange), the handle is duplicated into its user +// interface and the local handle is closed. +// + +#define DBGP_OPEN_APP_PROCESS_ACCESS \ + (PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | \ + PROCESS_DUP_HANDLE | PROCESS_TERMINATE | PROCESS_SET_PORT | \ + READ_CONTROL | PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD ) + +#define DBGP_DUP_APP_PROCESS_ACCESS \ + (PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | \ + PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | READ_CONTROL | PROCESS_CREATE_THREAD | PROCESS_TERMINATE ) + +// +// When a DLL is loaded or a process created, the file associated with the +// DLL/EXE is dupped into the UI. The following access is granted to the UI +// + +#define DBGP_DUP_APP_FILE_ACCESS ( SYNCHRONIZE | GENERIC_READ ) + +// +// Types +// + +// +// Each DebugUi client of Dbg is assigned a user interface structure. +// From this structure, all of the the threads controlled by the user +// interface can be found. +// + +// +// Subsystems are represented by the following data structure. All +// DbgSs APIs implicitly pass the address of this structure. +// + +typedef struct _DBGP_SUBSYSTEM { + CLIENT_ID SubsystemClientId; + HANDLE CommunicationPort; + HANDLE SubsystemProcessHandle; +} DBGP_SUBSYSTEM, *PDBGP_SUBSYSTEM; + +// +// Dbg maintains a handle to the DebugUi client represented by this data +// structure. The handle only has PROCESS_DUP_HANDLE access since this +// handle is only used to transfer handles into the DebugUi +// + +typedef struct _DBGP_USER_INTERFACE { + CLIENT_ID DebugUiClientId; + HANDLE CommunicationPort; + HANDLE DebugUiProcess; + HANDLE StateChangeSemaphore; + RTL_CRITICAL_SECTION UserInterfaceLock; + LIST_ENTRY AppProcessListHead; + LIST_ENTRY HashTableLinks; +} DBGP_USER_INTERFACE, *PDBGP_USER_INTERFACE; + +// +// Each application process is represented by the following structure +// + +typedef struct _DBGP_APP_PROCESS { + LIST_ENTRY AppThreadListHead; + LIST_ENTRY AppLinks; + LIST_ENTRY HashTableLinks; + CLIENT_ID AppClientId; + PDBGP_USER_INTERFACE UserInterface; + HANDLE DbgSrvHandleToProcess; + HANDLE HandleToProcess; +} DBGP_APP_PROCESS, *PDBGP_APP_PROCESS; + +// +// Each application thread is represented by the following structure +// + +typedef struct _DBGP_APP_THREAD { + LIST_ENTRY AppLinks; + LIST_ENTRY HashTableLinks; + CLIENT_ID AppClientId; + DBG_STATE CurrentState; + DBG_STATE ContinueState; + PDBGP_APP_PROCESS AppProcess; + PDBGP_USER_INTERFACE UserInterface; + HANDLE HandleToThread; + PDBGP_SUBSYSTEM Subsystem; + DBGSS_APIMSG LastSsApiMsg; +} DBGP_APP_THREAD, *PDBGP_APP_THREAD; + +typedef +NTSTATUS +(*PDBGSS_API) ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ); + +typedef +NTSTATUS +(*PDBGUI_API) ( + IN PDBGP_USER_INTERFACE UserInterface, + IN OUT PDBGUI_APIMSG ApiMsg + ); + +// +// Global Data +// + + +// +// Applications being debugged are assigned an DBGP_APP_THREAD structure. +// The application thread is linked into the DbgpAppClientIdHashTable +// while processing a "CreateThread" message. Insertion and deletion +// into this table is done under control of the DbgAppLock. +// + +#define DBGP_CLIENT_ID_HASHSIZE 32 + +#define DBGP_PROCESS_CLIENT_ID_TO_INDEX(pclient_id) (\ + ((ULONG)((pclient_id)->UniqueProcess))&(DBGP_CLIENT_ID_HASHSIZE-1)) + +#define DBGP_THREAD_CLIENT_ID_TO_INDEX(pclient_id) (\ + ((ULONG)((pclient_id)->UniqueThread))&(DBGP_CLIENT_ID_HASHSIZE-1)) + +RTL_CRITICAL_SECTION DbgpHashTableLock; +LIST_ENTRY DbgpAppThreadHashTable[DBGP_CLIENT_ID_HASHSIZE]; +LIST_ENTRY DbgpAppProcessHashTable[DBGP_CLIENT_ID_HASHSIZE]; +LIST_ENTRY DbgpUiHashTable[DBGP_CLIENT_ID_HASHSIZE]; + +HANDLE DbgpSsApiPort; +HANDLE DbgpUiApiPort; + +// +// Macros +// + +#define DBGP_CLIENT_IDS_EQUAL(pid1,pid2) (\ + (pid1)->UniqueProcess == (pid2)->UniqueProcess && \ + (pid1)->UniqueThread == (pid2)->UniqueThread ) + +#define DBGP_REPORTING_STATE_CHANGE(pAppThread) (\ + pAppThread->CurrentState != DbgIdle && pAppThread->CurrentState != DbgReplyPending ) + +// +// Implementation of DbgSs APIs +// + +NTSTATUS +DbgpSsException ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ); + +NTSTATUS +DbgpSsCreateThread ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ); + +NTSTATUS +DbgpSsCreateProcess ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ); + +NTSTATUS +DbgpSsExitThread ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ); + +NTSTATUS +DbgpSsExitProcess ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ); + +NTSTATUS +DbgpSsLoadDll ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ); + +NTSTATUS +DbgpSsUnloadDll ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ); + +// +// Implementation of DbgUi APIs +// + +NTSTATUS +DbgpUiWaitStateChange ( + IN PDBGP_USER_INTERFACE UserInterface, + IN OUT PDBGUI_APIMSG ApiMsg + ); + +NTSTATUS +DbgpUiContinue ( + IN PDBGP_USER_INTERFACE UserInterface, + IN OUT PDBGUI_APIMSG ApiMsg + ); + +// +// Private Prototypes +// + +NTSTATUS +DbgpSsApiLoop ( + IN PVOID ThreadParameter + ); + +NTSTATUS +DbgpUiApiLoop ( + IN PVOID ThreadParameter + ); + +NTSTATUS +DbgpInit( + VOID + ); + +// +// User Interface Support Routines +// + +PDBGP_USER_INTERFACE +DbgpIsUiInHashTable( + IN PCLIENT_ID DebugUiClientId + ); + +// +// App Support Routines +// + +PDBGP_APP_THREAD +DbgpIsAppInHashTable( + IN PCLIENT_ID AppClientId + ); + +PDBGP_APP_THREAD +DbgpLocateStateChangeApp( + IN PDBGP_USER_INTERFACE UserInterface, + OUT PDBG_STATE PreviousState + ); + +PDBGP_APP_PROCESS +DbgpIsAppProcessInHashTable( + IN PCLIENT_ID AppClientId + ); + +VOID +DbgpUiHasTerminated( + IN PCLIENT_ID DebugUiClientId + ); + +#if DBG + +// +// Dump Routines +// + +VOID +DbgpDumpUserInterface ( + IN PDBGP_USER_INTERFACE UserInterface + ); + +VOID +DbgpDumpSubsystem ( + IN PDBGP_SUBSYSTEM Subsystem + ); +#endif // DBG + +#endif // _DBGSRVP_ diff --git a/private/sm/server/dbgssapi.c b/private/sm/server/dbgssapi.c new file mode 100644 index 000000000..16f3b695e --- /dev/null +++ b/private/sm/server/dbgssapi.c @@ -0,0 +1,704 @@ +/*++ + +Copyright (c) 1989 - 1993 Microsoft Corporation + +Module Name: + + dbgssapi.c + +Abstract: + + This module implements the DbgSs APIs + +Author: + + Mark Lucovsky (markl) 22-Jan-1990 + +Revision History: + +--*/ + +#include "smsrvp.h" + +NTSTATUS +DbgpSsException ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ) +/*++ + +Routine Description: + + This function is called when a subsystem wants to + report that an exception has occured. + +Arguments: + + Subsystem - Supplies the address of the subsystem making the call + + ApiMsg - Supplies the DbgSs API message that contains the information + needed to complete this call. + +Return Value: + + DBG_REPLY_LATER - Successful receipt of message. A reply will be + generated when a continue is received from Ui. + + + TBD + +--*/ + +{ + PDBGP_APP_THREAD AppThread; + NTSTATUS ExceptionCode; + + // + // Locate AppThread + // + + AppThread = DbgpIsAppInHashTable(&ApiMsg->AppClientId); + + if ( !AppThread ) { + return STATUS_INVALID_CID; + } + + AppThread->Subsystem = Subsystem; + + RtlEnterCriticalSection(&AppThread->UserInterface->UserInterfaceLock); + + // + // Verify that the thread is DbgIdle (i.e. we are expecting a state change) + // + + if ( AppThread->CurrentState != DbgIdle ) { + RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock); + return DBG_APP_NOT_IDLE; + } + + ExceptionCode = ApiMsg->u.Exception.ExceptionRecord.ExceptionCode; + + if ( ExceptionCode == STATUS_BREAKPOINT ) { + AppThread->CurrentState = DbgBreakpointStateChange; + } else if ( ExceptionCode == STATUS_SINGLE_STEP ) { + AppThread->CurrentState = DbgSingleStepStateChange; + } else { + AppThread->CurrentState = DbgExceptionStateChange; + } + + AppThread->ContinueState = AppThread->CurrentState; + AppThread->LastSsApiMsg = *ApiMsg; + + NtReleaseSemaphore( + AppThread->UserInterface->StateChangeSemaphore, + 1, + NULL + ); + + RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock); + + return DBG_REPLY_LATER; +} + +NTSTATUS +DbgpSsCreateThread ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ) + +/*++ + +Routine Description: + + This function is called when a subsystem wants to + report that a thread has been created. + +Arguments: + + Subsystem - Supplies the address of the subsystem making the call + + ApiMsg - Supplies the DbgSs API message that contains the information + needed to complete this call. + +Return Value: + + DBG_REPLY_LATER - Successful receipt of message. A reply will be + generated when a continue is received from Ui. + + STATUS_INVALID_CID - Process that this thread is part of could not + be located. + + + TBD + +--*/ + +{ + PDBGP_APP_PROCESS AppProcess; + PDBGP_APP_THREAD AppThread; + NTSTATUS st; + OBJECT_ATTRIBUTES Obja; + + // + // Locate AppProcess this thread is a part of + // + + RtlEnterCriticalSection(&DbgpHashTableLock); + + AppProcess = DbgpIsAppProcessInHashTable(&ApiMsg->AppClientId); + + if ( !AppProcess ) { + RtlLeaveCriticalSection(&DbgpHashTableLock); + return STATUS_INVALID_CID; + } + + // + // Now look to see if a thread whose ClientId matches + // the new threads ClientId exists in the APP table. + // This check is not really necessary, its really just + // a question of trust of DbgSs APIs. + // + + AppThread = DbgpIsAppInHashTable(&ApiMsg->AppClientId); + + if ( AppThread ) { + RtlLeaveCriticalSection(&DbgpHashTableLock); + return STATUS_INVALID_CID; + } + + + // + // Allocate an initialize and application thread structure. + // Link this into its process and into the application + // hash table + // + + AppThread = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( DBG_TAG ), sizeof(DBGP_APP_THREAD)); + + if ( !AppThread ) { + RtlLeaveCriticalSection(&DbgpHashTableLock); + return STATUS_NO_MEMORY; + } + + AppThread->Subsystem = Subsystem; + + AppThread->CurrentState = DbgCreateThreadStateChange; + AppThread->ContinueState = DbgCreateThreadStateChange; + AppThread->AppProcess = AppProcess; + AppThread->UserInterface = AppProcess->UserInterface; + AppThread->AppClientId = ApiMsg->AppClientId; + AppThread->LastSsApiMsg = *ApiMsg; + + // + // Get a local handle to the thread. + // + + InitializeObjectAttributes(&Obja, NULL, 0, NULL, NULL); + st = NtOpenThread( + &AppThread->HandleToThread, + DBGP_OPEN_APP_THREAD_ACCESS, + &Obja, + &AppThread->AppClientId + ); + + if ( !NT_SUCCESS(st) ) { + AppThread->HandleToThread = NULL; + } + + + // + // Insert thread on its process app list + // + + RtlEnterCriticalSection(&AppThread->UserInterface->UserInterfaceLock); + + InsertTailList( + &AppProcess->AppThreadListHead, + &AppThread->AppLinks + ); + + // + // Insert thread in app hash table + // + + InsertTailList( + &DbgpAppThreadHashTable[DBGP_THREAD_CLIENT_ID_TO_INDEX(&AppThread->AppClientId)], + &AppThread->HashTableLinks + ); + NtReleaseSemaphore( + AppThread->UserInterface->StateChangeSemaphore, + 1, + NULL + ); + + RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock); + + RtlLeaveCriticalSection(&DbgpHashTableLock); + + + return DBG_REPLY_LATER; + +} + +NTSTATUS +DbgpSsCreateProcess ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ) + +/*++ + +Routine Description: + + This function is called when a subsystem wants to + report that a new process has been created. + +Arguments: + + Subsystem - Supplies the address of the subsystem making the call + + ApiMsg - Supplies the DbgSs API message that contains the information + needed to complete this call. + +Return Value: + + DBG_REPLY_LATER - Successful receipt of message. A reply will be + generated when a continue is received from Ui. + + STATUS_INVALID_CID - An invalid ClientId was specified for the + DebugUiClientId. + + + TBD + +--*/ + +{ + PDBGP_USER_INTERFACE UserInterface; + PDBGP_APP_PROCESS AppProcess; + PDBGP_APP_THREAD AppThread; + PDBGSS_CREATE_PROCESS args; + NTSTATUS st; + OBJECT_ATTRIBUTES Obja; + + args = &ApiMsg->u.CreateProcessInfo; + + // + // Locate user interface specified by DebugUiClientId + // + + RtlEnterCriticalSection(&DbgpHashTableLock); + + UserInterface = DbgpIsUiInHashTable(&args->DebugUiClientId); + + if ( !UserInterface ) { + RtlLeaveCriticalSection(&DbgpHashTableLock); + return STATUS_INVALID_CID; + } + + // + // Now look to see if a thread whose ClientId matches + // the new threads ClientId exists in the APP tables. + // This check is not really necessary, its really just + // a question of trust of DbgSs APIs. + // + + AppThread = DbgpIsAppInHashTable(&ApiMsg->AppClientId); + + if ( AppThread ) { + RtlLeaveCriticalSection(&DbgpHashTableLock); + return STATUS_INVALID_CID; + } + + + // + // Allocate an initialize and application thread and process structure. + // Link these into the user interface and into the application + // hash table + // + + AppProcess = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( DBG_TAG ), sizeof(DBGP_APP_PROCESS)); + + if ( !AppProcess ) { + RtlLeaveCriticalSection(&DbgpHashTableLock); + return STATUS_NO_MEMORY; + } + + AppThread = RtlAllocateHeap(RtlProcessHeap(), MAKE_TAG( DBG_TAG ), sizeof(DBGP_APP_THREAD)); + + if ( !AppThread ) { + RtlFreeHeap(RtlProcessHeap(),0,AppProcess); + RtlLeaveCriticalSection(&DbgpHashTableLock); + return STATUS_NO_MEMORY; + + } + AppThread->Subsystem = Subsystem; + + AppThread->CurrentState = DbgCreateProcessStateChange; + AppThread->CurrentState = DbgCreateProcessStateChange; + AppThread->AppProcess = AppProcess; + AppThread->UserInterface = UserInterface; + AppThread->AppClientId = ApiMsg->AppClientId; + AppThread->LastSsApiMsg = *ApiMsg; + + AppProcess->AppClientId.UniqueProcess = ApiMsg->AppClientId.UniqueProcess; + AppProcess->AppClientId.UniqueThread = NULL; + AppProcess->UserInterface = UserInterface; + InitializeListHead(&AppProcess->AppThreadListHead); + + InsertTailList( + &AppProcess->AppThreadListHead, + &AppThread->AppLinks + ); + + + // + // Get a local handle to the thread. + // + + InitializeObjectAttributes(&Obja, NULL, 0, NULL, NULL); + st = NtOpenThread( + &AppThread->HandleToThread, + DBGP_OPEN_APP_THREAD_ACCESS, + &Obja, + &AppThread->AppClientId + ); + + if ( !NT_SUCCESS(st) ) { + AppThread->HandleToThread = NULL; + } + + // + // Get a local handle to the process. + // + + InitializeObjectAttributes(&Obja, NULL, 0, NULL, NULL); + st = NtOpenProcess( + &AppProcess->DbgSrvHandleToProcess, + DBGP_OPEN_APP_PROCESS_ACCESS, + &Obja, + &AppThread->AppClientId + ); + + if ( !NT_SUCCESS(st) ) { + AppProcess->DbgSrvHandleToProcess = NULL; + } + + // + // Insert process on its user interfaces app list + // + + RtlEnterCriticalSection(&UserInterface->UserInterfaceLock); + + InsertTailList( + &UserInterface->AppProcessListHead, + &AppProcess->AppLinks + ); + + // + // Insert process in app hash table + // + + InsertTailList( + &DbgpAppProcessHashTable[DBGP_PROCESS_CLIENT_ID_TO_INDEX(&AppThread->AppClientId)], + &AppProcess->HashTableLinks + ); + + // + // Insert thread in app hash table + // + + InsertTailList( + &DbgpAppThreadHashTable[DBGP_THREAD_CLIENT_ID_TO_INDEX(&AppThread->AppClientId)], + &AppThread->HashTableLinks + ); + + NtReleaseSemaphore( + UserInterface->StateChangeSemaphore, + 1, + NULL + ); + + RtlLeaveCriticalSection(&UserInterface->UserInterfaceLock); + + RtlLeaveCriticalSection(&DbgpHashTableLock); + + + return DBG_REPLY_LATER; + +} + +NTSTATUS +DbgpSsExitThread ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ) + +/*++ + +Routine Description: + + This function is called when a subsystem wants to + report that a thread is exiting. + +Arguments: + + Subsystem - Supplies the address of the subsystem making the call + + ApiMsg - Supplies the DbgSs API message that contains the information + needed to complete this call. + +Return Value: + + DBG_REPLY_LATER - Successful receipt of message. A reply will be + generated when a continue is received from Ui. + + + TBD + +--*/ + +{ + PDBGP_APP_THREAD AppThread; + + // + // Locate AppThread + // + + AppThread = DbgpIsAppInHashTable(&ApiMsg->AppClientId); + + if ( !AppThread ) { + return STATUS_INVALID_CID; + } + + AppThread->Subsystem = Subsystem; + + RtlEnterCriticalSection(&AppThread->UserInterface->UserInterfaceLock); + + // + // Verify that the thread is DbgIdle (i.e. we are expecting a state change) + // + + if ( AppThread->CurrentState != DbgIdle ) { + DbgPrint("Not Idle\n"); + RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock); + return DBG_APP_NOT_IDLE; + } + + AppThread->CurrentState = DbgExitThreadStateChange; + AppThread->ContinueState = DbgExitThreadStateChange; + AppThread->LastSsApiMsg = *ApiMsg; + + NtReleaseSemaphore( + AppThread->UserInterface->StateChangeSemaphore, + 1, + NULL + ); + + RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock); + + return DBG_REPLY_LATER; +} + +NTSTATUS +DbgpSsExitProcess ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ) +/*++ + +Routine Description: + + This function is called when a subsystem wants to + report that a process is exiting. + +Arguments: + + Subsystem - Supplies the address of the subsystem making the call + + ApiMsg - Supplies the DbgSs API message that contains the information + needed to complete this call. + +Return Value: + + DBG_REPLY_LATER - Successful receipt of message. A reply will be + generated when a continue is received from Ui. + + + TBD + +--*/ + +{ + PDBGP_APP_THREAD AppThread; + + // + // Locate AppThread + // + + AppThread = DbgpIsAppInHashTable(&ApiMsg->AppClientId); + + if ( !AppThread ) { + return STATUS_INVALID_CID; + } + + AppThread->Subsystem = Subsystem; + + RtlEnterCriticalSection(&AppThread->UserInterface->UserInterfaceLock); + + // + // Verify that the thread is DbgIdle (i.e. we are expecting a state change) + // + + if ( AppThread->CurrentState != DbgIdle ) { + RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock); + return DBG_APP_NOT_IDLE; + } + + AppThread->CurrentState = DbgExitProcessStateChange; + AppThread->ContinueState = DbgExitProcessStateChange; + AppThread->LastSsApiMsg = *ApiMsg; + + NtReleaseSemaphore( + AppThread->UserInterface->StateChangeSemaphore, + 1, + NULL + ); + + RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock); + + return DBG_REPLY_LATER; +} + +NTSTATUS +DbgpSsLoadDll ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ) +/*++ + +Routine Description: + + This function is called when a subsystem wants to + report that a process has loaded a Dll. + +Arguments: + + Subsystem - Supplies the address of the subsystem making the call + + ApiMsg - Supplies the DbgSs API message that contains the information + needed to complete this call. + +Return Value: + + DBG_REPLY_LATER - Successful receipt of message. A reply will be + generated when a continue is received from Ui. + + + TBD + +--*/ + +{ + PDBGP_APP_THREAD AppThread; + + // + // Locate AppThread + // + + AppThread = DbgpIsAppInHashTable(&ApiMsg->AppClientId); + + if ( !AppThread ) { + return STATUS_INVALID_CID; + } + + AppThread->Subsystem = Subsystem; + + RtlEnterCriticalSection(&AppThread->UserInterface->UserInterfaceLock); + + // + // Verify that the thread is DbgIdle (i.e. we are expecting a state change) + // + + if ( AppThread->CurrentState != DbgIdle ) { + RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock); + return DBG_APP_NOT_IDLE; + } + + AppThread->CurrentState = DbgLoadDllStateChange; + AppThread->ContinueState = AppThread->CurrentState; + AppThread->LastSsApiMsg = *ApiMsg; + + NtReleaseSemaphore( + AppThread->UserInterface->StateChangeSemaphore, + 1, + NULL + ); + + RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock); + + return DBG_REPLY_LATER; +} + +NTSTATUS +DbgpSsUnloadDll ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ) +/*++ + +Routine Description: + + This function is called when a subsystem wants to + report that a process has unloaded a dll. + +Arguments: + + Subsystem - Supplies the address of the subsystem making the call + + ApiMsg - Supplies the DbgSs API message that contains the information + needed to complete this call. + +Return Value: + + DBG_REPLY_LATER - Successful receipt of message. A reply will be + generated when a continue is received from Ui. + + + TBD + +--*/ + +{ + PDBGP_APP_THREAD AppThread; + + // + // Locate AppThread + // + + AppThread = DbgpIsAppInHashTable(&ApiMsg->AppClientId); + + if ( !AppThread ) { + return STATUS_INVALID_CID; + } + + AppThread->Subsystem = Subsystem; + + RtlEnterCriticalSection(&AppThread->UserInterface->UserInterfaceLock); + + // + // Verify that the thread is DbgIdle (i.e. we are expecting a state change) + // + + if ( AppThread->CurrentState != DbgIdle ) { + RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock); + return DBG_APP_NOT_IDLE; + } + + AppThread->CurrentState = DbgUnloadDllStateChange; + AppThread->ContinueState = AppThread->CurrentState; + AppThread->LastSsApiMsg = *ApiMsg; + + NtReleaseSemaphore( + AppThread->UserInterface->StateChangeSemaphore, + 1, + NULL + ); + + RtlLeaveCriticalSection(&AppThread->UserInterface->UserInterfaceLock); + + return DBG_REPLY_LATER; +} diff --git a/private/sm/server/dbguiapi.c b/private/sm/server/dbguiapi.c new file mode 100644 index 000000000..07eb48e7b --- /dev/null +++ b/private/sm/server/dbguiapi.c @@ -0,0 +1,675 @@ +/*++ + +Copyright (c) 1989 - 1993 Microsoft Corporation + +Module Name: + + dbguiapi.c + +Abstract: + + This module implements the DbgUi APIs + +Author: + + Mark Lucovsky (markl) 23-Jan-1990 + +Revision History: + +--*/ + +#include "smsrvp.h" + +// +// Forward declarations. +// + +NTSTATUS +DbgpCreateProcess( + IN PDBGP_USER_INTERFACE UserInterface, + IN OUT PDBGP_APP_THREAD AppThread, + OUT PDBGUI_CREATE_PROCESS CreateProcessInfo + ); + +NTSTATUS +DbgpCreateThread( + IN PDBGP_USER_INTERFACE UserInterface, + IN OUT PDBGP_APP_THREAD AppThread, + OUT PDBGUI_CREATE_THREAD CreateThread + ); + +NTSTATUS +DbgpLoadDll( + IN PDBGP_USER_INTERFACE UserInterface, + IN OUT PDBGP_APP_THREAD AppThread, + OUT PDBGKM_LOAD_DLL LoadDll + ); + +NTSTATUS +DbgpUiWaitStateChange ( + IN PDBGP_USER_INTERFACE UserInterface, + IN OUT PDBGUI_APIMSG ApiMsg + ) + +/*++ + +Routine Description: + + This function is called when a user interface has waited + on its state change notification semaphore, and wants to + pickup a state change message. + +Arguments: + + UserInterface - Supplies the address of the user interface making the call + + ApiMsg - Supplies the DbgUi API message that contains the information + needed to complete this call. + +Return Value: + + STATUS_SUCCESS - A state change occured and is available in the + ApiMsg. + + DBG_NO_STATE_CHANGE - No state change was found for the calling + user interface. + +--*/ +{ + + NTSTATUS st; + PDBGP_APP_THREAD AppThread; + DBG_STATE PreviousState; + + st = STATUS_SUCCESS; + + // + // Scan the user interface's app list looking for an + // app whose State is not DbgIdle or DbgReplyPending + // + + AppThread = DbgpLocateStateChangeApp(UserInterface,&PreviousState); + + if ( !AppThread ) { + return DBG_NO_STATE_CHANGE; + } + + ApiMsg->u.WaitStateChange.NewState = PreviousState; + ApiMsg->u.WaitStateChange.AppClientId = AppThread->AppClientId; + + switch ( PreviousState ) { + + case DbgCreateThreadStateChange : + // + // Open the thread and Dup a handle over to the user + // interface. + // + + st = DbgpCreateThread( + UserInterface, + AppThread, + &ApiMsg->u.WaitStateChange.StateInfo.CreateThread + ); + break; + + case DbgCreateProcessStateChange : + + // + // Open the process, thread, and section, and Dup a handle + // over to the user interface. + // + + st = DbgpCreateProcess( + UserInterface, + AppThread, + &ApiMsg->u.WaitStateChange.StateInfo.CreateProcessInfo + ); + break; + + case DbgExitThreadStateChange : + ApiMsg->u.WaitStateChange.StateInfo.ExitThread = + AppThread->LastSsApiMsg.u.ExitThread; + break; + case DbgExitProcessStateChange : + ApiMsg->u.WaitStateChange.StateInfo.ExitProcess = + AppThread->LastSsApiMsg.u.ExitProcess; + break; + + case DbgLoadDllStateChange : + + // + // Dup File handle to the user interface + // + + st = DbgpLoadDll( + UserInterface, + AppThread, + &ApiMsg->u.WaitStateChange.StateInfo.LoadDll + ); + break; + + case DbgUnloadDllStateChange : + + // + // Dup section handle to the user interface + // + + ApiMsg->u.WaitStateChange.StateInfo.UnloadDll = + AppThread->LastSsApiMsg.u.UnloadDll; + break; + + case DbgExceptionStateChange : + case DbgBreakpointStateChange : + case DbgSingleStepStateChange : + ApiMsg->u.WaitStateChange.StateInfo.Exception = + AppThread->LastSsApiMsg.u.Exception; + break; + + default : + st = STATUS_NOT_IMPLEMENTED; + break; + } + + return st; +} + + +NTSTATUS +DbgpCreateThread( + IN PDBGP_USER_INTERFACE UserInterface, + IN OUT PDBGP_APP_THREAD AppThread, + OUT PDBGUI_CREATE_THREAD CreateThread + ) + +/*++ + +Routine Description: + + This function is called during the processing of a WaitStateChange + DbgUi API when the the state change for the App was + DbgCreateThreadStateChange. + + This functions main purpose is to dup a handle to the thread into + the thread's controlling user interface. + +Arguments: + + UserInterface - Supplies the address of the thread's user interface. + + AppThread - Supplies the address of the application thread. + + CreateThread - Supplies the address of the create thread message that + is being returned to the user interface. + +Return Value: + + TBD + +--*/ + +{ + NTSTATUS st; + + + CreateThread->HandleToThread = NULL; + CreateThread->NewThread = AppThread->LastSsApiMsg.u.CreateThread; + + // + // If handle to thread was successfully opened, + // then attempt to duplicate it into the user interface + // + + if ( AppThread->HandleToThread ) { + try { + st = NtDuplicateObject( + NtCurrentProcess(), + AppThread->HandleToThread, + UserInterface->DebugUiProcess, + &CreateThread->HandleToThread, + DBGP_DUP_APP_THREAD_ACCESS, + 0L, + DUPLICATE_CLOSE_SOURCE + ); + } + except ( GetExceptionCode() == STATUS_INVALID_HANDLE ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) { + st = STATUS_INVALID_HANDLE; + } + + if (!NT_SUCCESS(st)){ + st = DBG_UNABLE_TO_PROVIDE_HANDLE; + CreateThread->HandleToThread = NULL; + AppThread->HandleToThread = NULL; + } else { + + AppThread->HandleToThread = (HANDLE)((ULONG)CreateThread->HandleToThread | 1); + } + } else { + st = DBG_UNABLE_TO_PROVIDE_HANDLE; + } + + return st; +} + +NTSTATUS +DbgpCreateProcess( + IN PDBGP_USER_INTERFACE UserInterface, + IN OUT PDBGP_APP_THREAD AppThread, + OUT PDBGUI_CREATE_PROCESS CreateProcessInfo + ) + +/*++ + +Routine Description: + + This function is called during the processing of a WaitStateChange + DbgUi API when the the state change for the App was + DbgCreateProcessStateChange. + + This functions main purpose is to dup a handle to the thread, its + process, and the process's section into the thread's controlling + user interface. + +Arguments: + + UserInterface - Supplies the address of the thread's user interface. + + AppThread - Supplies the address of the application thread. + + CreateProcessInfo - Supplies the address of the create process message that + is being returned to the user interface. + +Return Value: + + TBD + +--*/ + +{ + NTSTATUS st; + NTSTATUS ReturnStatus; + + ReturnStatus = STATUS_SUCCESS; + + CreateProcessInfo->HandleToThread = NULL; + CreateProcessInfo->HandleToProcess = NULL; + + CreateProcessInfo->NewProcess = AppThread->LastSsApiMsg.u.CreateProcessInfo.NewProcess; + + CreateProcessInfo->NewProcess.FileHandle = NULL; + + // + // If handle to thread was successfully opened, + // then attempt to duplicate it into the user interface + // + + if ( AppThread->HandleToThread ) { + try { + st = NtDuplicateObject( + NtCurrentProcess(), + AppThread->HandleToThread, + UserInterface->DebugUiProcess, + &CreateProcessInfo->HandleToThread, + DBGP_DUP_APP_THREAD_ACCESS, + 0L, + DUPLICATE_CLOSE_SOURCE + ); + } + except ( GetExceptionCode() == STATUS_INVALID_HANDLE ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) { + st = STATUS_INVALID_HANDLE; + } + + if (!NT_SUCCESS(st)){ + ReturnStatus = DBG_UNABLE_TO_PROVIDE_HANDLE; + CreateProcessInfo->HandleToThread = NULL; + AppThread->HandleToThread = NULL; + } else { + AppThread->HandleToThread = (HANDLE)((ULONG)CreateProcessInfo->HandleToThread | 1); + } + } else { + ReturnStatus = DBG_UNABLE_TO_PROVIDE_HANDLE; + } + + // + // If handle to process was successfully opened, + // then attempt to duplicate it into the user interface + // + + if ( AppThread->AppProcess->DbgSrvHandleToProcess ) { + st = NtDuplicateObject( + NtCurrentProcess(), + AppThread->AppProcess->DbgSrvHandleToProcess, + UserInterface->DebugUiProcess, + &CreateProcessInfo->HandleToProcess, + DBGP_DUP_APP_PROCESS_ACCESS, + 0L, + 0L + ); + + if (!NT_SUCCESS(st)){ + ReturnStatus = DBG_UNABLE_TO_PROVIDE_HANDLE; + CreateProcessInfo->HandleToProcess = NULL; + AppThread->AppProcess->HandleToProcess = NULL; + } else { + + AppThread->AppProcess->HandleToProcess = + CreateProcessInfo->HandleToProcess; + + if ( AppThread->LastSsApiMsg.u.CreateProcessInfo.NewProcess.FileHandle ) { + + st = NtDuplicateObject( + AppThread->AppProcess->DbgSrvHandleToProcess, + AppThread->LastSsApiMsg.u.CreateProcessInfo.NewProcess.FileHandle, + UserInterface->DebugUiProcess, + &CreateProcessInfo->NewProcess.FileHandle, + DBGP_DUP_APP_FILE_ACCESS, + 0L, + 0L + ); + + if (!NT_SUCCESS(st)){ + ReturnStatus = DBG_UNABLE_TO_PROVIDE_HANDLE; + CreateProcessInfo->NewProcess.FileHandle = NULL; + } + } + + } + } else { + ReturnStatus = DBG_UNABLE_TO_PROVIDE_HANDLE; + } + + return ReturnStatus; +} + + +NTSTATUS +DbgpLoadDll( + IN PDBGP_USER_INTERFACE UserInterface, + IN OUT PDBGP_APP_THREAD AppThread, + OUT PDBGKM_LOAD_DLL LoadDll + ) + +/*++ + +Routine Description: + + This function is called during the processing of a WaitStateChange + DbgUi API when the the state change for the App was + DbgLoadDllStateChange. + + This functions main purpose is to dup a handle to file into the + thread's controlling user interface. + +Arguments: + + UserInterface - Supplies the address of the thread's user interface. + + AppThread - Supplies the address of the application thread. + + LoadDll - Supplies the address of the load dll message that + is being returned to the user interface. + +Return Value: + + TBD + +--*/ + +{ + NTSTATUS st; + NTSTATUS ReturnStatus; + + ReturnStatus = STATUS_SUCCESS; + + + *LoadDll = AppThread->LastSsApiMsg.u.LoadDll; + + st = NtDuplicateObject( + AppThread->AppProcess->DbgSrvHandleToProcess, + AppThread->LastSsApiMsg.u.LoadDll.FileHandle, + UserInterface->DebugUiProcess, + &LoadDll->FileHandle, + DBGP_DUP_APP_FILE_ACCESS, + 0L, + 0L + ); + + if (!NT_SUCCESS(st)){ + ReturnStatus = DBG_UNABLE_TO_PROVIDE_HANDLE; + LoadDll->FileHandle = NULL; + } + + return ReturnStatus; +} + +NTSTATUS +DbgpUiContinue ( + IN PDBGP_USER_INTERFACE UserInterface, + IN OUT PDBGUI_APIMSG ApiMsg + ) + +/*++ + +Routine Description: + + This function is called when a user interface has received + a state change message, and wants to continue one of its + application threads. Continuing translates into a reply + to an outstanding DbgSs API. + +Arguments: + + UserInterface - Supplies the address of the user interface making the call + + ApiMsg - Supplies the DbgUi API message that contains the information + needed to complete this call. + +Return Value: + + STATUS_SUCCESS - Successful call to DbgUiContinue + + STATUS_INVALID_CID - An invalid ClientId was specified for the + AppClientId, or the specified Application was not waiting + for a continue. + + STATUS_INVALID_PARAMETER - An invalid continue status was specified. + +--*/ +{ + + NTSTATUS st; + PDBGP_APP_THREAD AppThread; + PDBGUI_CONTINUE args; + DBGSRV_APIMSG ContinueMsg; + PDBGP_SUBSYSTEM Subsystem; + + args = &ApiMsg->u.Continue; + + // + // Make sure that Continue status is valid + // + + switch (args->ContinueStatus) { + + case DBG_EXCEPTION_HANDLED : + case DBG_EXCEPTION_NOT_HANDLED : + case DBG_TERMINATE_THREAD : + case DBG_TERMINATE_PROCESS : + case DBG_CONTINUE : + break; + default: + return STATUS_INVALID_PARAMETER; + } + + RtlEnterCriticalSection(&DbgpHashTableLock); + + + AppThread = DbgpIsAppInHashTable(&args->AppClientId); + + if ( !AppThread ) { + RtlLeaveCriticalSection(&DbgpHashTableLock); + return STATUS_INVALID_CID; + } + + Subsystem = AppThread->Subsystem; + + // + // Now determine what type of continue this is. Depending on + // the threads continue state certain things need to happen. + // If we are continuing an exit thread or exit process, data + // structures need to be torn down, and handles in the user + // interface need to be closed. + // + + RtlEnterCriticalSection(&UserInterface->UserInterfaceLock); + + // + // Disallow continues on Apps that have not been picked up + // yet. + // + + if ( AppThread->CurrentState != DbgReplyPending ) { + RtlLeaveCriticalSection(&UserInterface->UserInterfaceLock); + RtlLeaveCriticalSection(&DbgpHashTableLock); + return STATUS_INVALID_CID; + } + + AppThread->CurrentState = DbgIdle; + + DBGSRV_FORMAT_API_MSG(ContinueMsg,DbgSrvContinueApi,0L,AppThread->LastSsApiMsg.ContinueKey); + ContinueMsg.ReturnedStatus = args->ContinueStatus; + + switch (AppThread->ContinueState) { + + // + // These involve data structure tear down + // + + case DbgExitThreadStateChange : + + // + // Try to close the handle to the thread that + // the user interface has. + // + + if ( AppThread->HandleToThread ) { + try { + NtDuplicateObject( + AppThread->UserInterface->DebugUiProcess, + AppThread->HandleToThread, + NULL, + NULL, + 0L, + 0L, + DUPLICATE_CLOSE_SOURCE + ); + } + except ( GetExceptionCode() == STATUS_INVALID_HANDLE ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) { + ; + } + } + AppThread->HandleToThread = NULL; + + // + // delink the thread from its process, and deallocate it. + // + + RemoveEntryList(&AppThread->AppLinks); + + // + // Remove the thread from the thread hash table, and + // deallocate the thread + // + + RemoveEntryList(&AppThread->HashTableLinks); + + RtlFreeHeap(RtlProcessHeap(), 0,AppThread); + + break; + + case DbgExitProcessStateChange : + // + // Try to close the handle to the thread that + // the user interface has. + // + + if ( AppThread->HandleToThread ) { + try { + st = NtDuplicateObject( + AppThread->UserInterface->DebugUiProcess, + AppThread->HandleToThread, + NULL, + NULL, + 0L, + 0L, + DUPLICATE_CLOSE_SOURCE + ); + } + except ( GetExceptionCode() == STATUS_INVALID_HANDLE ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) { + ; + } + } + AppThread->HandleToThread = NULL; + + // + // Try to close the handle to the process + // that we gave to the user interface + // + + if ( AppThread->AppProcess->DbgSrvHandleToProcess ) { + try { + st = NtDuplicateObject( + AppThread->UserInterface->DebugUiProcess, + AppThread->AppProcess->HandleToProcess, + NULL, + NULL, + 0L, + 0L, + DUPLICATE_CLOSE_SOURCE + ); + } + except ( GetExceptionCode() == STATUS_INVALID_HANDLE ? EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH ) { + ; + } + NtClose(AppThread->AppProcess->DbgSrvHandleToProcess); + } + + // + // Remove the thread from the thread hash table, + // the process from the process hash table, and + // the process from its user interface. + // + + RemoveEntryList(&AppThread->HashTableLinks); + RemoveEntryList(&AppThread->AppProcess->HashTableLinks); + RemoveEntryList(&AppThread->AppProcess->AppLinks); + + RtlFreeHeap(RtlProcessHeap(), 0,AppThread->AppProcess); + RtlFreeHeap(RtlProcessHeap(), 0,AppThread); + + break; + + // + // No work needed + // + + case DbgCreateThreadStateChange : + case DbgCreateProcessStateChange : + case DbgExceptionStateChange : + case DbgBreakpointStateChange : + case DbgSingleStepStateChange : + case DbgLoadDllStateChange : + case DbgUnloadDllStateChange : + break; + + default: + ASSERT(FALSE); + } + + RtlLeaveCriticalSection(&UserInterface->UserInterfaceLock); + RtlLeaveCriticalSection(&DbgpHashTableLock); + + st = NtRequestPort(Subsystem->CommunicationPort, (PPORT_MESSAGE)&ContinueMsg); + ASSERT(NT_SUCCESS(st)); + + return st; +} diff --git a/private/sm/server/dbguisup.c b/private/sm/server/dbguisup.c new file mode 100644 index 000000000..2fbcfb0e1 --- /dev/null +++ b/private/sm/server/dbguisup.c @@ -0,0 +1,242 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + dbguisup.c + +Abstract: + + This module implements support routines for User Interfaces + +Author: + + Mark Lucovsky (markl) 23-Jan-1990 + +Revision History: + +--*/ + +#include "smsrvp.h" + +PDBGP_USER_INTERFACE +DbgpIsUiInHashTable( + IN PCLIENT_ID DebugUiClientId + ) + +/*++ + +Routine Description: + + This routine scans the user interface hash table looking + for a user interface that matches the specified client id. + + If a matching user interface is found, then its address is + returned. + +Arguments: + + DebugUiClientId - Supplies the address of ClientId of the user + interface to locate. + +Return Value: + + NULL - No user interface with a matching ClientId could be located. + + NON-NULL - Returns the address of the user interface that matches + the specified ClientId. + +--*/ + +{ + ULONG Index; + PLIST_ENTRY Head, Next; + PDBGP_USER_INTERFACE UserInterface; + + RtlEnterCriticalSection(&DbgpHashTableLock); + + Index = DBGP_PROCESS_CLIENT_ID_TO_INDEX(DebugUiClientId); + + Head = &DbgpUiHashTable[Index]; + Next = Head->Flink; + + while ( Next != Head ) { + UserInterface = CONTAINING_RECORD(Next,DBGP_USER_INTERFACE,HashTableLinks); + if ( DBGP_CLIENT_IDS_EQUAL( + &UserInterface->DebugUiClientId, + DebugUiClientId + )) { + RtlLeaveCriticalSection(&DbgpHashTableLock); + return UserInterface; + } + Next = Next->Flink; + } + + RtlLeaveCriticalSection(&DbgpHashTableLock); + return NULL; +} + +VOID +DbgpUiHasTerminated( + IN PCLIENT_ID DebugUiClientId + ) + +/*++ + +Routine Description: + + This routine processes client died messages from a user interface. + Its purpose is to cleanup all control blocks/data structures associated + with a user-interface. + +Arguments: + + DebugUiClientId - Supplies the client id of the terminated Ui. + +Return Value: + + None. + +--*/ + +{ + + PLIST_ENTRY HeadProcess, NextProcess; + PLIST_ENTRY HeadThread, NextThread; + PDBGP_APP_THREAD AppThread; + PDBGP_APP_PROCESS AppProcess; + NTSTATUS st; + PDBGP_USER_INTERFACE UserInterface; + DBGSRV_APIMSG ContinueMsg; + HANDLE NullPort; + HANDLE Thread; + OBJECT_ATTRIBUTES ThreadObja; + KERNEL_USER_TIMES Times; + + InitializeObjectAttributes(&ThreadObja, NULL, 0, NULL, NULL); + NullPort = NULL; + RtlEnterCriticalSection(&DbgpHashTableLock); + UserInterface = DbgpIsUiInHashTable(DebugUiClientId); + if ( !UserInterface ) { + RtlLeaveCriticalSection(&DbgpHashTableLock); + return; + } + + // + // User interface was located, so take it out of the list. + // + + RemoveEntryList(&UserInterface->HashTableLinks); + RtlLeaveCriticalSection(&DbgpHashTableLock); + + // + // Now process each thread and process owned by the user-interface + // + + HeadProcess = &UserInterface->AppProcessListHead; + NextProcess = HeadProcess->Flink; + + while ( NextProcess != HeadProcess ) { + + // + // For each process managed by the user interface, + // scan its thread list + // + + AppProcess = CONTAINING_RECORD(NextProcess,DBGP_APP_PROCESS,AppLinks); + NtSetInformationProcess( + AppProcess->DbgSrvHandleToProcess, + ProcessDebugPort, + &NullPort, + sizeof(HANDLE) + ); + + HeadThread = &AppProcess->AppThreadListHead; + NextThread = HeadThread->Flink; + + while ( NextThread != HeadThread ) { + AppThread = CONTAINING_RECORD(NextThread,DBGP_APP_THREAD,AppLinks); + + // + // Terminate the thread if not already dead + // + + st = NtOpenThread( + &Thread, + THREAD_TERMINATE | THREAD_QUERY_INFORMATION, + &ThreadObja, + &AppThread->AppClientId + ); + + if ( NT_SUCCESS(st) ) { + + // + // check exit time + // + + st = NtQueryInformationThread( + Thread, + ThreadTimes, + (PVOID) &Times, + sizeof(Times), + NULL + ); + if ( NT_SUCCESS(st) ) { + if ( Times.ExitTime.LowPart == 0 && + Times.ExitTime.HighPart == 0 ) { + NtTerminateThread(Thread,DBG_TERMINATE_PROCESS); + } + } + + NtClose(Thread); + } + + if ( AppThread->CurrentState == DbgReplyPending ) { + + AppThread->CurrentState = DbgIdle; + DBGSRV_FORMAT_API_MSG(ContinueMsg,DbgSrvContinueApi,0L,AppThread->LastSsApiMsg.ContinueKey); + ContinueMsg.ReturnedStatus = DBG_CONTINUE; + st = NtRequestPort( + AppThread->Subsystem->CommunicationPort, + (PPORT_MESSAGE)&ContinueMsg + ); + ASSERT(NT_SUCCESS(st)); + + } + else { + if ( DBGP_REPORTING_STATE_CHANGE(AppThread) ) { + AppThread->ContinueState = AppThread->CurrentState; + AppThread->CurrentState = DbgIdle; + DBGSRV_FORMAT_API_MSG(ContinueMsg,DbgSrvContinueApi,0L,AppThread->LastSsApiMsg.ContinueKey); + ContinueMsg.ReturnedStatus = DBG_CONTINUE; + st = NtRequestPort( + AppThread->Subsystem->CommunicationPort, + (PPORT_MESSAGE)&ContinueMsg + ); + } + } + + if ( AppThread->HandleToThread && + !AppThread->HandleToThread & 1 ) { + NtClose(AppThread->HandleToThread); + } + + NextThread = NextThread->Flink; + RemoveEntryList(&AppThread->AppLinks); + RemoveEntryList(&AppThread->HashTableLinks); + RtlFreeHeap(RtlProcessHeap(), 0,AppThread); + } + NtClose(AppProcess->DbgSrvHandleToProcess); + + NextProcess = NextProcess->Flink; + RemoveEntryList(&AppProcess->HashTableLinks); + RemoveEntryList(&AppProcess->AppLinks); + RtlFreeHeap(RtlProcessHeap(), 0,AppProcess); + } + NtClose(UserInterface->CommunicationPort); + NtClose(UserInterface->DebugUiProcess); + NtClose(UserInterface->StateChangeSemaphore); + RtlDeleteCriticalSection(&UserInterface->UserInterfaceLock); + RtlFreeHeap(RtlProcessHeap(), 0,UserInterface); +} diff --git a/private/sm/server/makefile b/private/sm/server/makefile new file mode 100644 index 000000000..6ee4f43fa --- /dev/null +++ b/private/sm/server/makefile @@ -0,0 +1,6 @@ +# +# DO NOT EDIT THIS FILE!!! Edit .\sources. if you want to add a new source +# file to this component. This file merely indirects to the real make file +# that is shared by all the components of NT OS/2 +# +!INCLUDE $(NTMAKEENV)\makefile.def diff --git a/private/sm/server/smdbg.c b/private/sm/server/smdbg.c new file mode 100644 index 000000000..5baf3b03f --- /dev/null +++ b/private/sm/server/smdbg.c @@ -0,0 +1,124 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + smdbg.c + +Abstract: + + Dbg Subsystem Support for sm + +Author: + + Mark Lucovsky (markl) 01-Feb-1990 + +Revision History: + +--*/ + +#include "smsrvp.h" +#include <string.h> + + +// +// BUGBUG fix this loop +// + +NTSTATUS +SmpUiLookup( + IN PCLIENT_ID AppClientId, + OUT PCLIENT_ID DebugUiClientId + ) +{ + PLIST_ENTRY Head, Next; + PSMPPROCESS AppProcess; + + Head = &NativeProcessList; + Next = Head->Flink; + + while ( Next != Head ) { + AppProcess = CONTAINING_RECORD(Next,SMPPROCESS,Links); + + if ( AppProcess->ConnectionKey.UniqueProcess == AppClientId->UniqueProcess) { + *DebugUiClientId = AppProcess->DebugUiClientId; + return STATUS_SUCCESS; + } + Next = Next->Flink; + } + + return STATUS_UNSUCCESSFUL; +} + +VOID +SmpDebugProcessExit( + IN PCLIENT_ID AppClientId + ) +{ + PLIST_ENTRY Head, Next; + PSMPPROCESS AppProcess; + + Head = &NativeProcessList; + Next = Head->Flink; + + while ( Next != Head ) { + AppProcess = CONTAINING_RECORD(Next,SMPPROCESS,Links); + + if ( AppProcess->ConnectionKey.UniqueProcess == AppClientId->UniqueProcess) { + RemoveEntryList(&AppProcess->Links); + RtlFreeHeap(SmpHeap, 0,AppProcess); + return; + } + Next = Next->Flink; + } + + return; +} + + +NTSTATUS +SmpKmApiMsgFilter ( + IN OUT PDBGKM_APIMSG ApiMsg + ) +{ + switch ( ApiMsg->ApiNumber ) { + + case DbgKmExitProcessApi : + + // + // Tear down debug related data structures + // + + SmpDebugProcessExit(&ApiMsg->h.ClientId); + break; + + default : + break; + } + + return DBG_CONTINUE; +} + + +NTSTATUS +DbgpInit(); + +NTSTATUS +SmpLoadDbgSs( + IN PUNICODE_STRING DbgSsName + ) +{ + NTSTATUS st; + + st = DbgpInit(); + if ( !NT_SUCCESS(st) ) { + return st; + } + + st = DbgSsInitialize(SmpDebugPort,SmpUiLookup,NULL,SmpKmApiMsgFilter); + ASSERT(NT_SUCCESS(st)); + + SmpDbgSsLoaded = TRUE; + return STATUS_SUCCESS; +} diff --git a/private/sm/server/sminit.c b/private/sm/server/sminit.c new file mode 100644 index 000000000..3bfd82a9c --- /dev/null +++ b/private/sm/server/sminit.c @@ -0,0 +1,4694 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sminit.c + +Abstract: + + Session Manager Initialization + +Author: + + Mark Lucovsky (markl) 04-Oct-1989 + +Revision History: + +--*/ + +#include "smsrvp.h" +#include <stdio.h> +#include <string.h> + +void +SmpDisplayString( char *s ); + +// #define SMP_SHOW_REGISTRY_DATA 1 + + +#define MAX_PAGING_FILES 16 + + +// +// Protection mode flags +// + +#define SMP_NO_PROTECTION (0x0) +#define SMP_STANDARD_PROTECTION (0x1) + +#define SMP_PROTECTION_REQUIRED \ + (SMP_STANDARD_PROTECTION) + + +ULONG CountPageFiles; +LONG PageFileMinSizes[ MAX_PAGING_FILES ]; +LONG PageFileMaxSizes[ MAX_PAGING_FILES ]; +UNICODE_STRING PageFileSpecs[ MAX_PAGING_FILES ]; +PSECURITY_DESCRIPTOR SmpPrimarySecurityDescriptor; +SECURITY_DESCRIPTOR SmpPrimarySDBody; +PSECURITY_DESCRIPTOR SmpLiberalSecurityDescriptor; +SECURITY_DESCRIPTOR SmpLiberalSDBody; +PSECURITY_DESCRIPTOR SmpKnownDllsSecurityDescriptor; +SECURITY_DESCRIPTOR SmpKnownDllsSDBody; +PSECURITY_DESCRIPTOR SmpApiPortSecurityDescriptor; +SECURITY_DESCRIPTOR SmpApiPortSDBody; +ULONG SmpProtectionMode = 0; + +#if DBG +BOOLEAN SmpEnableDots = FALSE; +#else +BOOLEAN SmpEnableDots = TRUE; +#endif + + +WCHAR InitialCommandBuffer[ 256 ]; + +UNICODE_STRING SmpDebugKeyword; +UNICODE_STRING SmpASyncKeyword; +UNICODE_STRING SmpAutoChkKeyword; +UNICODE_STRING SmpKnownDllPath; + +HANDLE SmpWindowsSubSysProcess; + +typedef struct _SMP_REGISTRY_VALUE { + LIST_ENTRY Entry; + UNICODE_STRING Name; + UNICODE_STRING Value; + LPSTR AnsiValue; +} SMP_REGISTRY_VALUE, *PSMP_REGISTRY_VALUE; + +LIST_ENTRY SmpBootExecuteList; +LIST_ENTRY SmpPagingFileList; +LIST_ENTRY SmpDosDevicesList; +LIST_ENTRY SmpFileRenameList; +LIST_ENTRY SmpKnownDllsList; +LIST_ENTRY SmpExcludeKnownDllsList; +LIST_ENTRY SmpSubSystemList; +LIST_ENTRY SmpSubSystemsToLoad; +LIST_ENTRY SmpSubSystemsToDefer; +LIST_ENTRY SmpExecuteList; + + +NTSTATUS +SmpCreateSecurityDescriptors( + IN BOOLEAN InitialCall + ); + +NTSTATUS +SmpLoadDataFromRegistry( + OUT PUNICODE_STRING InitialCommand + ); + +NTSTATUS +SmpCreateDynamicEnvironmentVariables( + VOID + ); + +PSMP_REGISTRY_VALUE +SmpFindRegistryValue( + IN PLIST_ENTRY ListHead, + IN PWSTR Name + ); + +NTSTATUS +SmpSaveRegistryValue( + IN OUT PLIST_ENTRY ListHead, + IN PWSTR Name, + IN PWSTR Value OPTIONAL, + IN BOOLEAN CheckForDuplicate + ); + +#ifdef SMP_SHOW_REGISTRY_DATA +VOID +SmpDumpQuery( + IN PCHAR RoutineName, + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength + ); +#endif + + +NTSTATUS +SmpConfigureProtectionMode( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +NTSTATUS +SmpConfigureObjectDirectories( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +NTSTATUS +SmpConfigureExecute( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +NTSTATUS +SmpConfigureFileRenames( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +NTSTATUS +SmpConfigureMemoryMgmt( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +NTSTATUS +SmpConfigureDosDevices( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +NTSTATUS +SmpConfigureKnownDlls( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +NTSTATUS +SmpConfigureExcludeKnownDlls( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +NTSTATUS +SmpConfigureSubSystems( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +NTSTATUS +SmpConfigureEnvironment( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ); + +RTL_QUERY_REGISTRY_TABLE SmpRegistryConfigurationTable[] = { + + // + // Note that the SmpConfigureProtectionMode entry should preceed others + // to ensure we set up the right protection for use by the others. + // + + {SmpConfigureProtectionMode, 0, + L"ProtectionMode", NULL, + REG_DWORD, (PVOID)0, 0}, + + {SmpConfigureObjectDirectories, 0, + L"ObjectDirectories", NULL, + REG_MULTI_SZ, (PVOID)L"\\Windows\0\\RPC Control\0", 0}, + + {SmpConfigureExecute, 0, + L"BootExecute", &SmpBootExecuteList, + REG_MULTI_SZ, L"autocheck \\SystemRoot\\Windows\\System32\\AutoChk.exe *\0", 0}, + + {SmpConfigureFileRenames, RTL_QUERY_REGISTRY_DELETE, + L"PendingFileRenameOperations", &SmpFileRenameList, + REG_NONE, NULL, 0}, + + {SmpConfigureExcludeKnownDlls, 0, + L"ExcludeFromKnownDlls", &SmpExcludeKnownDllsList, + REG_MULTI_SZ, L"\0", 0}, + + {NULL, RTL_QUERY_REGISTRY_SUBKEY, + L"Memory Management", NULL, + REG_NONE, NULL, 0}, + + {SmpConfigureMemoryMgmt, 0, + L"PagingFiles", &SmpPagingFileList, + REG_MULTI_SZ, "?:\\pagefile.sys 10 60\0", 0}, + + {SmpConfigureDosDevices, RTL_QUERY_REGISTRY_SUBKEY, + L"DOS Devices", &SmpDosDevicesList, + REG_NONE, NULL, 0}, + + {SmpConfigureKnownDlls, RTL_QUERY_REGISTRY_SUBKEY, + L"KnownDlls", &SmpKnownDllsList, + REG_NONE, NULL, 0}, + + {SmpConfigureEnvironment, RTL_QUERY_REGISTRY_SUBKEY, + L"Environment", NULL, + REG_NONE, NULL, 0}, + + {SmpConfigureSubSystems, RTL_QUERY_REGISTRY_SUBKEY, + L"SubSystems", &SmpSubSystemList, + REG_NONE, NULL, 0}, + + {SmpConfigureSubSystems, RTL_QUERY_REGISTRY_NOEXPAND, + L"Required", &SmpSubSystemList, + REG_MULTI_SZ, L"Debug\0Windows\0", 0}, + + {SmpConfigureSubSystems, RTL_QUERY_REGISTRY_NOEXPAND, + L"Optional", &SmpSubSystemList, + REG_NONE, NULL, 0}, + + {SmpConfigureSubSystems, 0, + L"Kmode", &SmpSubSystemList, + REG_NONE, NULL, 0}, + + {SmpConfigureExecute, RTL_QUERY_REGISTRY_TOPKEY, + L"Execute", &SmpExecuteList, + REG_NONE, NULL, 0}, + + {NULL, 0, + NULL, NULL, + REG_NONE, NULL, 0} + +}; + + +NTSTATUS +SmpInvokeAutoChk( + IN PUNICODE_STRING ImageFileName, + IN PUNICODE_STRING CurrentDirectory, + IN PUNICODE_STRING Arguments, + IN ULONG Flags + ); + +NTSTATUS +SmpLoadSubSystem( + IN PUNICODE_STRING ImageFileName, + IN PUNICODE_STRING CurrentDirectory, + IN PUNICODE_STRING CommandLine, + IN ULONG Flags + ); + +NTSTATUS +SmpExecuteCommand( + IN PUNICODE_STRING CommandLine, + IN ULONG Flags + ); + +NTSTATUS +SmpInitializeDosDevices( VOID ); + +NTSTATUS +SmpInitializeKnownDlls( VOID ); + +VOID +SmpProcessFileRenames( VOID ); + +NTSTATUS +SmpParseToken( + IN PUNICODE_STRING Source, + IN BOOLEAN RemainderOfSource, + OUT PUNICODE_STRING Token + ); + +NTSTATUS +SmpParseCommandLine( + IN PUNICODE_STRING CommandLine, + OUT PULONG Flags, + OUT PUNICODE_STRING ImageFileName, + OUT PUNICODE_STRING ImageFileDirectory, + OUT PUNICODE_STRING Arguments + ); + +#define SMP_DEBUG_FLAG 0x00000001 +#define SMP_ASYNC_FLAG 0x00000002 +#define SMP_AUTOCHK_FLAG 0x00000004 +#define SMP_SUBSYSTEM_FLAG 0x00000008 +#define SMP_IMAGE_NOT_FOUND 0x00000010 +#define SMP_DONT_START 0x00000020 + +ULONG +SmpConvertInteger( + IN PWSTR String + ); + +NTSTATUS +SmpAddPagingFile( + IN PUNICODE_STRING PagingFileSpec + ); + +NTSTATUS +SmpCreatePagingFile( + PUNICODE_STRING PagingFileSpec, + LARGE_INTEGER MinPagingFileSize, + LARGE_INTEGER MaxPagingFileSize + ); + +NTSTATUS +SmpCreatePagingFiles( VOID ); + +VOID +SmpTranslateSystemPartitionInformation( VOID ); + +#define VALUE_BUFFER_SIZE (sizeof(KEY_VALUE_PARTIAL_INFORMATION) + 256 * sizeof(WCHAR)) + +// +// local Macros +// + +// +// VOID +// SmpSetDaclDefaulted( +// IN POBJECT_ATTRIBUTES ObjectAttributes, +// OUT PSECURITY_DESCRIPTOR_CONTROL CurrentSdControl +// ) +// +// Description: +// +// This routine will set the DaclDefaulted flag of the DACL passed +// via the ObjectAttributes parameter. If the ObjectAttributes do +// not include a SecurityDescriptor, then no action is taken. +// +// Parameters: +// +// ObjectAttributes - The object attributes whose security descriptor is +// to have its DaclDefaulted flag set. +// +// CurrentSdControl - Receives the current value of the security descriptor's +// control flags. This may be used in a subsequent call to +// SmpRestoreDaclDefaulted() to restore the flag to its original state. +// + +#define SmpSetDaclDefaulted( OA, SDC ) \ + if( (OA)->SecurityDescriptor != NULL) { \ + (*SDC) = ((PISECURITY_DESCRIPTOR)((OA)->SecurityDescriptor))->Control & \ + SE_DACL_DEFAULTED; \ + ((PISECURITY_DESCRIPTOR)((OA)->SecurityDescriptor))->Control |= \ + SE_DACL_DEFAULTED; \ + } + + +// +// VOID +// SmpRestoreDaclDefaulted( +// IN POBJECT_ATTRIBUTES ObjectAttributes, +// IN SECURITY_DESCRIPTOR_CONTROL OriginalSdControl +// ) +// +// Description: +// +// This routine will set the DaclDefaulted flag of the DACL back to +// a prior state (indicated by the value in OriginalSdControl). +// +// Parameters: +// +// ObjectAttributes - The object attributes whose security descriptor is +// to have its DaclDefaulted flag restored. If the object attributes +// have no security descriptor, then no action is taken. +// +// OriginalSdControl - The original value of the security descriptor's +// control flags. This typically is obtained via a prior call to +// SmpSetDaclDefaulted(). +// + +#define SmpRestoreDaclDefaulted( OA, SDC ) \ + if( (OA)->SecurityDescriptor != NULL) { \ + ((PISECURITY_DESCRIPTOR)((OA)->SecurityDescriptor))->Control = \ + (((PISECURITY_DESCRIPTOR)((OA)->SecurityDescriptor))->Control & \ + ~SE_DACL_DEFAULTED) | \ + (SDC & SE_DACL_DEFAULTED); \ + } + +// +// routines +// + + + +BOOLEAN +SmpQueryRegistrySosOption( + VOID + ) + +/*++ + +Routine Description: + + This function queries the registry to determine if the loadoptions + boot environment variable contains the string "SOS". + + HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control:SystemStartOptions + +Arguments: + + None. + +Return Value: + + TRUE if "SOS" was set. Otherwise FALSE. + +--*/ + +{ + + NTSTATUS Status; + UNICODE_STRING KeyName; + UNICODE_STRING ValueName; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE Key; + WCHAR ValueBuffer[VALUE_BUFFER_SIZE]; + PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo; + ULONG ValueLength; + + // + // Open the registry key. + // + + KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer; + RtlInitUnicodeString(&KeyName, + L"\\Registry\\Machine\\System\\CurrentControlSet\\Control"); + + InitializeObjectAttributes(&ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL); + + Status = NtOpenKey(&Key, KEY_READ, &ObjectAttributes); + if (!NT_SUCCESS(Status)) { + KdPrint(("SMSS: can't open control key: 0x%x\n", Status)); + return FALSE; + } + + // + // Query the key value. + // + + RtlInitUnicodeString(&ValueName, L"SystemStartOptions"); + Status = NtQueryValueKey(Key, + &ValueName, + KeyValuePartialInformation, + (PVOID)KeyValueInfo, + VALUE_BUFFER_SIZE, + &ValueLength); + + ASSERT(ValueLength < VALUE_BUFFER_SIZE); + + NtClose(Key); + if (!NT_SUCCESS(Status)) { + KdPrint(("SMSS: can't query value key: 0x%x\n", Status)); + return FALSE; + } + + // + // Check is "sos" or "SOS" ois specified. + // + + if (NULL != wcsstr((PWCHAR)&KeyValueInfo->Data, L"SOS") || + NULL != wcsstr((PWCHAR)&KeyValueInfo->Data, L"sos")) { + return TRUE; + } + + return FALSE; +} + +NTSTATUS +SmpSaveRegistryValue( + IN OUT PLIST_ENTRY ListHead, + IN PWSTR Name, + IN PWSTR Value OPTIONAL, + IN BOOLEAN CheckForDuplicate + ) +{ + PLIST_ENTRY Next; + PSMP_REGISTRY_VALUE p; + UNICODE_STRING UnicodeName; + UNICODE_STRING UnicodeValue; + ANSI_STRING AnsiString; + + RtlInitUnicodeString( &UnicodeName, Name ); + RtlInitUnicodeString( &UnicodeValue, Value ); + if (CheckForDuplicate) { + Next = ListHead->Flink; + p = NULL; + while ( Next != ListHead ) { + p = CONTAINING_RECORD( Next, + SMP_REGISTRY_VALUE, + Entry + ); + if (!RtlCompareUnicodeString( &p->Name, &UnicodeName, TRUE )) { + if ((!ARGUMENT_PRESENT( Value ) && p->Value.Buffer == NULL) || + (ARGUMENT_PRESENT( Value ) && + !RtlCompareUnicodeString( &p->Value, &UnicodeValue, TRUE ) + ) + ) { + return( STATUS_OBJECT_NAME_EXISTS ); + } + + break; + } + + Next = Next->Flink; + p = NULL; + } + } + else { + p = NULL; + } + + if (p == NULL) { + p = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), sizeof( *p ) + UnicodeName.MaximumLength ); + if (p == NULL) { + return( STATUS_NO_MEMORY ); + } + + InitializeListHead( &p->Entry ); + p->Name.Buffer = (PWSTR)(p+1); + p->Name.Length = UnicodeName.Length; + p->Name.MaximumLength = UnicodeName.MaximumLength; + RtlMoveMemory( p->Name.Buffer, + UnicodeName.Buffer, + UnicodeName.MaximumLength + ); + p->Value.Buffer = NULL; + InsertTailList( ListHead, &p->Entry ); + } + + if (p->Value.Buffer != NULL) { + RtlFreeHeap( RtlProcessHeap(), 0, p->Value.Buffer ); + } + + if (ARGUMENT_PRESENT( Value )) { + p->Value.Buffer = (PWSTR)RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), + UnicodeValue.MaximumLength + ); + if (p->Value.Buffer == NULL) { + RemoveEntryList( &p->Entry ); + RtlFreeHeap( RtlProcessHeap(), 0, p ); + return( STATUS_NO_MEMORY ); + } + + p->Value.Length = UnicodeValue.Length; + p->Value.MaximumLength = UnicodeValue.MaximumLength; + RtlMoveMemory( p->Value.Buffer, + UnicodeValue.Buffer, + UnicodeValue.MaximumLength + ); + p->AnsiValue = (LPSTR)RtlAllocateHeap( RtlProcessHeap(), + MAKE_TAG( INIT_TAG ), + (UnicodeValue.Length / sizeof( WCHAR )) + 1 + ); + if (p->AnsiValue == NULL) { + RtlFreeHeap( RtlProcessHeap(), 0, p->Value.Buffer ); + RemoveEntryList( &p->Entry ); + RtlFreeHeap( RtlProcessHeap(), 0, p ); + return( STATUS_NO_MEMORY ); + } + + AnsiString.Buffer = p->AnsiValue; + AnsiString.Length = 0; + AnsiString.MaximumLength = (UnicodeValue.Length / sizeof( WCHAR )) + 1; + RtlUnicodeStringToAnsiString( &AnsiString, &UnicodeValue, FALSE ); + } + else { + RtlInitUnicodeString( &p->Value, NULL ); + } + + return( STATUS_SUCCESS ); +} + + + +PSMP_REGISTRY_VALUE +SmpFindRegistryValue( + IN PLIST_ENTRY ListHead, + IN PWSTR Name + ) +{ + PLIST_ENTRY Next; + PSMP_REGISTRY_VALUE p; + UNICODE_STRING UnicodeName; + + RtlInitUnicodeString( &UnicodeName, Name ); + Next = ListHead->Flink; + while ( Next != ListHead ) { + p = CONTAINING_RECORD( Next, + SMP_REGISTRY_VALUE, + Entry + ); + if (!RtlCompareUnicodeString( &p->Name, &UnicodeName, TRUE )) { + return( p ); + } + + Next = Next->Flink; + } + + return( NULL ); +} + +NTSTATUS +SmpInit( + OUT PUNICODE_STRING InitialCommand, + OUT PHANDLE WindowsSubSystem + ) +{ + NTSTATUS st; + OBJECT_ATTRIBUTES ObjA; + HANDLE SmpApiConnectionPort; + UNICODE_STRING Unicode; + NTSTATUS Status; + ULONG HardErrorMode; + + SmBaseTag = RtlCreateTagHeap( RtlProcessHeap(), + 0, + L"SMSS!", + L"INIT\0" + L"DBG\0" + L"SM\0" + ); + // + // Make sure we specify hard error popups + // + + HardErrorMode = 1; + NtSetInformationProcess( NtCurrentProcess(), + ProcessDefaultHardErrorMode, + (PVOID) &HardErrorMode, + sizeof( HardErrorMode ) + ); + + RtlInitUnicodeString( &SmpSubsystemName, L"NT-Session Manager" ); + + + RtlInitializeCriticalSection(&SmpKnownSubSysLock); + InitializeListHead(&SmpKnownSubSysHead); + + RtlInitializeCriticalSection(&SmpSessionListLock); + InitializeListHead(&SmpSessionListHead); + SmpNextSessionId = 1; + SmpNextSessionIdScanMode = FALSE; + SmpDbgSsLoaded = FALSE; + + // + // Initialize security descriptors to grant wide access + // (protection mode not yet read in from registry). + // + + st = SmpCreateSecurityDescriptors( TRUE ); + if ( !NT_SUCCESS(st) ) { + return(st); + } + + + + InitializeListHead(&NativeProcessList); + + SmpHeap = RtlProcessHeap(); + + RtlInitUnicodeString( &Unicode, L"\\SmApiPort" ); + InitializeObjectAttributes( &ObjA, &Unicode, 0, NULL, SmpApiPortSecurityDescriptor); + + st = NtCreatePort( + &SmpApiConnectionPort, + &ObjA, + sizeof(SBCONNECTINFO), + sizeof(SMMESSAGE_SIZE), + sizeof(SBAPIMSG) * 32 + ); + ASSERT( NT_SUCCESS(st) ); + + SmpDebugPort = SmpApiConnectionPort; + + st = RtlCreateUserThread( + NtCurrentProcess(), + NULL, + FALSE, + 0L, + 0L, + 0L, + SmpApiLoop, + (PVOID) SmpApiConnectionPort, + NULL, + NULL + ); + ASSERT( NT_SUCCESS(st) ); + + st = RtlCreateUserThread( + NtCurrentProcess(), + NULL, + FALSE, + 0L, + 0L, + 0L, + SmpApiLoop, + (PVOID) SmpApiConnectionPort, + NULL, + NULL + ); + ASSERT( NT_SUCCESS(st) ); + + // + // Configure the system + // + + Status = SmpLoadDataFromRegistry( InitialCommand ); + + if (NT_SUCCESS( Status )) { + *WindowsSubSystem = SmpWindowsSubSysProcess; + } + return( Status ); +} + +typedef struct _SMP_ACQUIRE_STATE { + HANDLE Token; + PTOKEN_PRIVILEGES OldPrivileges; + PTOKEN_PRIVILEGES NewPrivileges; + UCHAR OldPrivBuffer[ 1024 ]; +} SMP_ACQUIRE_STATE, *PSMP_ACQUIRE_STATE; + +NTSTATUS +SmpAcquirePrivilege( + ULONG Privilege, + PVOID *ReturnedState + ) +{ + PSMP_ACQUIRE_STATE State; + ULONG cbNeeded; + LUID LuidPrivilege; + NTSTATUS Status; + + // + // Make sure we have access to adjust and to get the old token privileges + // + + *ReturnedState = NULL; + State = RtlAllocateHeap( RtlProcessHeap(), + MAKE_TAG( INIT_TAG ), + sizeof(SMP_ACQUIRE_STATE) + + sizeof(TOKEN_PRIVILEGES) + + (1 - ANYSIZE_ARRAY) * sizeof(LUID_AND_ATTRIBUTES) + ); + if (State == NULL) { + return STATUS_NO_MEMORY; + } + Status = NtOpenProcessToken( + NtCurrentProcess(), + TOKEN_ADJUST_PRIVILEGES | TOKEN_QUERY, + &State->Token + ); + + if ( !NT_SUCCESS( Status )) { + RtlFreeHeap( RtlProcessHeap(), 0, State ); + return Status; + } + + State->NewPrivileges = (PTOKEN_PRIVILEGES)(State+1); + State->OldPrivileges = (PTOKEN_PRIVILEGES)(State->OldPrivBuffer); + + // + // Initialize the privilege adjustment structure + // + + LuidPrivilege = RtlConvertUlongToLuid(Privilege); + State->NewPrivileges->PrivilegeCount = 1; + State->NewPrivileges->Privileges[0].Luid = LuidPrivilege; + State->NewPrivileges->Privileges[0].Attributes = SE_PRIVILEGE_ENABLED; + + // + // Enable the privilege + // + + cbNeeded = sizeof( State->OldPrivBuffer ); + Status = NtAdjustPrivilegesToken( State->Token, + FALSE, + State->NewPrivileges, + cbNeeded, + State->OldPrivileges, + &cbNeeded + ); + + + + if (Status == STATUS_BUFFER_TOO_SMALL) { + State->OldPrivileges = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), cbNeeded ); + if (State->OldPrivileges == NULL) { + Status = STATUS_NO_MEMORY; + } + else { + Status = NtAdjustPrivilegesToken( State->Token, + FALSE, + State->NewPrivileges, + cbNeeded, + State->OldPrivileges, + &cbNeeded + ); + } + } + + // + // STATUS_NOT_ALL_ASSIGNED means that the privilege isn't + // in the token, so we can't proceed. + // + // This is a warning level status, so map it to an error status. + // + + if (Status == STATUS_NOT_ALL_ASSIGNED) { + Status = STATUS_PRIVILEGE_NOT_HELD; + } + + + if (!NT_SUCCESS( Status )) { + if (State->OldPrivileges != (PTOKEN_PRIVILEGES)(State->OldPrivBuffer)) { + RtlFreeHeap( RtlProcessHeap(), 0, State->OldPrivileges ); + } + + NtClose( State->Token ); + RtlFreeHeap( RtlProcessHeap(), 0, State ); + return Status; + } + + *ReturnedState = State; + return STATUS_SUCCESS; +} + + +VOID +SmpReleasePrivilege( + PVOID StatePointer + ) +{ + PSMP_ACQUIRE_STATE State = (PSMP_ACQUIRE_STATE)StatePointer; + + NtAdjustPrivilegesToken( State->Token, + FALSE, + State->OldPrivileges, + 0, + NULL, + NULL + ); + + if (State->OldPrivileges != (PTOKEN_PRIVILEGES)(State->OldPrivBuffer)) { + RtlFreeHeap( RtlProcessHeap(), 0, State->OldPrivileges ); + } + + NtClose( State->Token ); + RtlFreeHeap( RtlProcessHeap(), 0, State ); + return; +} + + +NTSTATUS +SmpLoadDataFromRegistry( + OUT PUNICODE_STRING InitialCommand + ) + +/*++ + +Routine Description: + + This function loads all of the configurable data for the NT Session + Manager from the registry. + +Arguments: + + None + +Return Value: + + Status of operation + +--*/ + +{ + NTSTATUS Status; + PLIST_ENTRY Head, Next; + PSMP_REGISTRY_VALUE p; + PVOID OriginalEnvironment; + + RtlInitUnicodeString( &SmpDebugKeyword, L"debug" ); + RtlInitUnicodeString( &SmpASyncKeyword, L"async" ); + RtlInitUnicodeString( &SmpAutoChkKeyword, L"autocheck" ); + + InitializeListHead( &SmpBootExecuteList ); + InitializeListHead( &SmpPagingFileList ); + InitializeListHead( &SmpDosDevicesList ); + InitializeListHead( &SmpFileRenameList ); + InitializeListHead( &SmpKnownDllsList ); + InitializeListHead( &SmpExcludeKnownDllsList ); + InitializeListHead( &SmpSubSystemList ); + InitializeListHead( &SmpSubSystemsToLoad ); + InitializeListHead( &SmpSubSystemsToDefer ); + InitializeListHead( &SmpExecuteList ); + + Status = RtlCreateEnvironment( TRUE, &SmpDefaultEnvironment ); + if (!NT_SUCCESS( Status )) { + KdPrint(("SMSS: Unable to allocate default environment - Status == %X\n", Status )); + return( Status ); + } + + // + // In order to track growth in smpdefaultenvironment, make it sm's environment + // while doing the registry groveling and then restore it + // + + OriginalEnvironment = NtCurrentPeb()->ProcessParameters->Environment; + NtCurrentPeb()->ProcessParameters->Environment = SmpDefaultEnvironment; + Status = RtlQueryRegistryValues( RTL_REGISTRY_CONTROL, + L"Session Manager", + SmpRegistryConfigurationTable, + NULL, + NULL + ); + + SmpDefaultEnvironment = NtCurrentPeb()->ProcessParameters->Environment; + NtCurrentPeb()->ProcessParameters->Environment = OriginalEnvironment; + + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: RtlQueryRegistryValues failed - Status == %lx\n", Status )); + return( Status ); + } + + Status = SmpInitializeDosDevices(); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Unable to initialize DosDevices configuration - Status == %lx\n", Status )); + return( Status ); + } + + Head = &SmpBootExecuteList; + while (!IsListEmpty( Head )) { + Next = RemoveHeadList( Head ); + p = CONTAINING_RECORD( Next, + SMP_REGISTRY_VALUE, + Entry + ); +#ifdef SMP_SHOW_REGISTRY_DATA + DbgPrint( "SMSS: BootExecute( %wZ )\n", &p->Name ); +#endif + SmpExecuteCommand( &p->Name, 0 ); + RtlFreeHeap( RtlProcessHeap(), 0, p ); + } + + SmpProcessFileRenames(); + + Status = SmpInitializeKnownDlls(); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Unable to initialize KnownDll configuration - Status == %lx\n", Status )); + return( Status ); + } + + + // + // Process the list of paging files. + // + + Head = &SmpPagingFileList; + while (!IsListEmpty( Head )) { + Next = RemoveHeadList( Head ); + p = CONTAINING_RECORD( Next, + SMP_REGISTRY_VALUE, + Entry + ); +#ifdef SMP_SHOW_REGISTRY_DATA + DbgPrint( "SMSS: PagingFile( %wZ )\n", &p->Name ); +#endif + SmpAddPagingFile( &p->Name ); + RtlFreeHeap( RtlProcessHeap(), 0, p ); + } + + // + // Create any paging files specified in NT section(s) + // + + SmpCreatePagingFiles(); + + // + // Finish registry initialization + // + + NtInitializeRegistry(FALSE); + + Status = SmpCreateDynamicEnvironmentVariables( ); + if (!NT_SUCCESS( Status )) { + return Status; + } + + // + // Translate the system partition information stored during IoInitSystem into + // a DOS path and store in Win32-standard location. + // + + SmpTranslateSystemPartitionInformation(); + + Head = &SmpSubSystemList; + while (!IsListEmpty( Head )) { + Next = RemoveHeadList( Head ); + p = CONTAINING_RECORD( Next, + SMP_REGISTRY_VALUE, + Entry + ); + if ( !_wcsicmp( p->Name.Buffer, L"Kmode" )) { + BOOLEAN TranslationStatus; + UNICODE_STRING FileName; + + TranslationStatus = RtlDosPathNameToNtPathName_U( + p->Value.Buffer, + &FileName, + NULL, + NULL + ); + + if ( TranslationStatus ) { + PVOID State; + + Status = SmpAcquirePrivilege( SE_LOAD_DRIVER_PRIVILEGE, &State ); + if (NT_SUCCESS( Status )) { + Status = NtSetSystemInformation( + SystemExtendServiceTableInformation, + (PVOID)&FileName, + sizeof(FileName) + ); + RtlFreeHeap(RtlProcessHeap(), 0, FileName.Buffer); + SmpReleasePrivilege( State ); + if ( !NT_SUCCESS(Status) ) { + Status = STATUS_SUCCESS; + } + } + } + else { + Status = STATUS_OBJECT_PATH_SYNTAX_BAD; + } + } +#ifdef SMP_SHOW_REGISTRY_DATA + DbgPrint( "SMSS: Unused SubSystem( %wZ = %wZ )\n", &p->Name, &p->Value ); +#endif + RtlFreeHeap( RtlProcessHeap(), 0, p ); + } + + Head = &SmpSubSystemsToLoad; + while (!IsListEmpty( Head )) { + Next = RemoveHeadList( Head ); + p = CONTAINING_RECORD( Next, + SMP_REGISTRY_VALUE, + Entry + ); +#ifdef SMP_SHOW_REGISTRY_DATA + DbgPrint( "SMSS: Loaded SubSystem( %wZ = %wZ )\n", &p->Name, &p->Value ); +#endif + if (!_wcsicmp( p->Name.Buffer, L"debug" )) { + SmpExecuteCommand( &p->Value, SMP_SUBSYSTEM_FLAG | SMP_DEBUG_FLAG ); + } + else { + SmpExecuteCommand( &p->Value, SMP_SUBSYSTEM_FLAG ); + } + RtlFreeHeap( RtlProcessHeap(), 0, p ); + } + + + Head = &SmpExecuteList; + if (!IsListEmpty( Head )) { + Next = Head->Blink; + p = CONTAINING_RECORD( Next, + SMP_REGISTRY_VALUE, + Entry + ); + RemoveEntryList( &p->Entry ); + *InitialCommand = p->Name; + + // + // This path is only taken when people want to run ntsd -p -1 winlogon + // + // This is nearly impossible to do in a race free manner. In some + // cases, we can get in a state where we can not properly fail + // a debug API. This is due to the subsystem switch that occurs + // when ntsd is invoked on csr. If csr is relatively idle, this + // does not occur. If it is active when you attach, then we can get + // into a potential race. The slimy fix is to do a 5 second delay + // if the command line is anything other that the default. + // + + { + LARGE_INTEGER DelayTime; + DelayTime.QuadPart = Int32x32To64( 5000, -10000 ); + NtDelayExecution( + FALSE, + &DelayTime + ); + } + } + else { + RtlInitUnicodeString( InitialCommand, L"winlogon.exe" ); + InitialCommandBuffer[ 0 ] = UNICODE_NULL; + LdrQueryImageFileExecutionOptions( InitialCommand, + L"Debugger", + REG_SZ, + InitialCommandBuffer, + sizeof( InitialCommandBuffer ), + NULL + ); + if (InitialCommandBuffer[ 0 ] != UNICODE_NULL) { + wcscat( InitialCommandBuffer, L" " ); + wcscat( InitialCommandBuffer, InitialCommand->Buffer ); + RtlInitUnicodeString( InitialCommand, InitialCommandBuffer ); + KdPrint(( "SMSS: InitialCommand == '%wZ'\n", InitialCommand )); + } + } + + while (!IsListEmpty( Head )) { + Next = RemoveHeadList( Head ); + p = CONTAINING_RECORD( Next, + SMP_REGISTRY_VALUE, + Entry + ); +#ifdef SMP_SHOW_REGISTRY_DATA + DbgPrint( "SMSS: Execute( %wZ )\n", &p->Name ); +#endif + SmpExecuteCommand( &p->Name, 0 ); + RtlFreeHeap( RtlProcessHeap(), 0, p ); + } + +#ifdef SMP_SHOW_REGISTRY_DATA + DbgPrint( "SMSS: InitialCommand( %wZ )\n", InitialCommand ); +#endif + return( Status ); +} + + +NTSTATUS +SmpCreateDynamicEnvironmentVariables( + VOID + ) +{ + NTSTATUS Status; + SYSTEM_BASIC_INFORMATION SystemInfo; + SYSTEM_PROCESSOR_INFORMATION ProcessorInfo; + OBJECT_ATTRIBUTES ObjectAttributes; + UNICODE_STRING KeyName; + UNICODE_STRING ValueName; + PWSTR ValueData; + WCHAR ValueBuffer[ 256 ]; + WCHAR ValueBuffer1[ 256 ]; + PKEY_VALUE_PARTIAL_INFORMATION KeyValueInfo; + ULONG ValueLength; + HANDLE Key, Key1; + + Status = NtQuerySystemInformation( SystemBasicInformation, + &SystemInfo, + sizeof( SystemInfo ), + NULL + ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Unable to query system basic information - %x\n", Status )); + return Status; + } + + Status = NtQuerySystemInformation( SystemProcessorInformation, + &ProcessorInfo, + sizeof( ProcessorInfo ), + NULL + ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Unable to query system processor information - %x\n", Status )); + return Status; + } + + RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\Session Manager\\Environment" ); + InitializeObjectAttributes( &ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + Status = NtOpenKey( &Key, GENERIC_WRITE, &ObjectAttributes ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Unable to open %wZ - %x\n", &KeyName, Status )); + return Status; + } + + RtlInitUnicodeString( &ValueName, L"OS" ); + ValueData = L"Windows_NT"; + Status = NtSetValueKey( Key, + &ValueName, + 0, + REG_SZ, + ValueData, + (wcslen( ValueData ) + 1) * sizeof( WCHAR ) + ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Failed writing %wZ environment variable - %x\n", &ValueName, Status )); + goto failexit; + } + + RtlInitUnicodeString( &ValueName, L"PROCESSOR_ARCHITECTURE" ); + switch( ProcessorInfo.ProcessorArchitecture ) { + case PROCESSOR_ARCHITECTURE_INTEL: + ValueData = L"x86"; + break; + + case PROCESSOR_ARCHITECTURE_MIPS: + ValueData = L"MIPS"; + break; + + case PROCESSOR_ARCHITECTURE_ALPHA: + ValueData = L"ALPHA"; + break; + + case PROCESSOR_ARCHITECTURE_PPC: + ValueData = L"PPC"; + break; + + default: + ValueData = L"Unknown"; + break; + } + + Status = NtSetValueKey( Key, + &ValueName, + 0, + REG_SZ, + ValueData, + (wcslen( ValueData ) + 1) * sizeof( WCHAR ) + ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Failed writing %wZ environment variable - %x\n", &ValueName, Status )); + goto failexit; + } + + RtlInitUnicodeString( &ValueName, L"PROCESSOR_LEVEL" ); + switch( ProcessorInfo.ProcessorArchitecture ) { + case PROCESSOR_ARCHITECTURE_MIPS: + // + // Multiple MIPS level by 1000 so 4 becomes 4000 + // + swprintf( ValueBuffer, L"%u", ProcessorInfo.ProcessorLevel * 1000 ); + break; + + case PROCESSOR_ARCHITECTURE_PPC: + // + // Just output the ProcessorLevel in decimal. + // + swprintf( ValueBuffer, L"%u", ProcessorInfo.ProcessorLevel ); + break; + + case PROCESSOR_ARCHITECTURE_INTEL: + case PROCESSOR_ARCHITECTURE_ALPHA: + default: + // + // All others use a single level number + // + swprintf( ValueBuffer, L"%u", ProcessorInfo.ProcessorLevel ); + break; + } + Status = NtSetValueKey( Key, + &ValueName, + 0, + REG_SZ, + ValueBuffer, + (wcslen( ValueBuffer ) + 1) * sizeof( WCHAR ) + ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Failed writing %wZ environment variable - %x\n", &ValueName, Status )); + goto failexit; + } + + RtlInitUnicodeString( &KeyName, L"\\Registry\\Machine\\Hardware\\Description\\System\\CentralProcessor\\0" ); + InitializeObjectAttributes( &ObjectAttributes, + &KeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + Status = NtOpenKey( &Key1, KEY_READ, &ObjectAttributes ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Unable to open %wZ - %x\n", &KeyName, Status )); + goto failexit; + } + RtlInitUnicodeString( &ValueName, L"Identifier" ); + KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer; + Status = NtQueryValueKey( Key1, + &ValueName, + KeyValuePartialInformation, + (PVOID)KeyValueInfo, + sizeof( ValueBuffer ), + &ValueLength + ); + if (!NT_SUCCESS( Status )) { + NtClose( Key1 ); + KdPrint(( "SMSS: Unable to read %wZ\\%wZ - %x\n", &KeyName, &ValueName, Status )); + goto failexit; + } + + ValueData = (PWSTR)KeyValueInfo->Data; + RtlInitUnicodeString( &ValueName, L"VendorIdentifier" ); + KeyValueInfo = (PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer1; + Status = NtQueryValueKey( Key1, + &ValueName, + KeyValuePartialInformation, + (PVOID)KeyValueInfo, + sizeof( ValueBuffer1 ), + &ValueLength + ); + NtClose( Key1 ); + if (NT_SUCCESS( Status )) { + swprintf( ValueData + wcslen( ValueData ), + L", %ws", + (PWSTR)KeyValueInfo->Data + ); + } + + RtlInitUnicodeString( &ValueName, L"PROCESSOR_IDENTIFIER" ); + Status = NtSetValueKey( Key, + &ValueName, + 0, + REG_SZ, + ValueData, + (wcslen( ValueData ) + 1) * sizeof( WCHAR ) + ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Failed writing %wZ environment variable - %x\n", &ValueName, Status )); + goto failexit; + } + + RtlInitUnicodeString( &ValueName, L"PROCESSOR_REVISION" ); + switch( ProcessorInfo.ProcessorArchitecture ) { + case PROCESSOR_ARCHITECTURE_INTEL: + if ((ProcessorInfo.ProcessorRevision >> 8) == 0xFF) { + // + // Intel 386/486 are An stepping format + // + swprintf( ValueBuffer, L"%02x", + ProcessorInfo.ProcessorRevision & 0xFF + ); + _wcsupr( ValueBuffer ); + break; + } + + // Fall through for Cyrix/NextGen 486 and Pentium processors. + + case PROCESSOR_ARCHITECTURE_PPC: + // + // Intel and PowerPC use fixed point binary number + // Output is 4 hex digits, no formatting. + // + swprintf( ValueBuffer, L"%04x", ProcessorInfo.ProcessorRevision ); + break; + + case PROCESSOR_ARCHITECTURE_ALPHA: + swprintf( ValueBuffer, L"Model %c, Pass %u", + 'A' + (ProcessorInfo.ProcessorRevision >> 8), + ProcessorInfo.ProcessorRevision & 0xFF + ); + swprintf( ValueBuffer, L"%u", ProcessorInfo.ProcessorRevision ); + break; + + case PROCESSOR_ARCHITECTURE_MIPS: + default: + // + // All others use a single revision number + // + swprintf( ValueBuffer, L"%u", ProcessorInfo.ProcessorRevision ); + break; + } + + Status = NtSetValueKey( Key, + &ValueName, + 0, + REG_SZ, + ValueBuffer, + (wcslen( ValueBuffer ) + 1) * sizeof( WCHAR ) + ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Failed writing %wZ environment variable - %x\n", &ValueName, Status )); + goto failexit; + } + + RtlInitUnicodeString( &ValueName, L"NUMBER_OF_PROCESSORS" ); + swprintf( ValueBuffer, L"%u", SystemInfo.NumberOfProcessors ); + Status = NtSetValueKey( Key, + &ValueName, + 0, + REG_SZ, + ValueBuffer, + (wcslen( ValueBuffer ) + 1) * sizeof( WCHAR ) + ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Failed writing %wZ environment variable - %x\n", &ValueName, Status )); + goto failexit; + } + +failexit: + NtClose( Key ); + return Status; +} + + +NTSTATUS +SmpInitializeDosDevices( VOID ) +{ + NTSTATUS Status; + PLIST_ENTRY Head, Next; + PSMP_REGISTRY_VALUE p; + UNICODE_STRING UnicodeString; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE LinkHandle; + SECURITY_DESCRIPTOR_CONTROL OriginalSdControl; + + // + // Do DosDevices initialization - the directory object is created in I/O init + // + + RtlInitUnicodeString( &UnicodeString, L"\\??" ); + InitializeObjectAttributes( &ObjectAttributes, + &UnicodeString, + OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT, + NULL, + NULL + ); + Status = NtOpenDirectoryObject( &SmpDosDevicesObjectDirectory, + DIRECTORY_ALL_ACCESS, + &ObjectAttributes + ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Unable to open %wZ directory - Status == %lx\n", &UnicodeString, Status )); + return( Status ); + } + + + // + // Process the list of defined DOS devices and create their + // associated symbolic links in the \DosDevices object directory. + // + + Head = &SmpDosDevicesList; + while (!IsListEmpty( Head )) { + Next = RemoveHeadList( Head ); + p = CONTAINING_RECORD( Next, + SMP_REGISTRY_VALUE, + Entry + ); +#ifdef SMP_SHOW_REGISTRY_DATA + DbgPrint( "SMSS: DosDevices( %wZ = %wZ )\n", &p->Name, &p->Value ); +#endif + InitializeObjectAttributes( &ObjectAttributes, + &p->Name, + OBJ_CASE_INSENSITIVE | OBJ_PERMANENT | OBJ_OPENIF, + SmpDosDevicesObjectDirectory, + SmpPrimarySecurityDescriptor + ); + SmpSetDaclDefaulted( &ObjectAttributes, &OriginalSdControl ); //Use inheritable protection if available + Status = NtCreateSymbolicLinkObject( &LinkHandle, + SYMBOLIC_LINK_ALL_ACCESS, + &ObjectAttributes, + &p->Value + ); + + if (Status == STATUS_OBJECT_NAME_EXISTS) { + NtMakeTemporaryObject( LinkHandle ); + NtClose( LinkHandle ); + if (p->Value.Length != 0) { + ObjectAttributes.Attributes &= ~OBJ_OPENIF; + Status = NtCreateSymbolicLinkObject( &LinkHandle, + SYMBOLIC_LINK_ALL_ACCESS, + &ObjectAttributes, + &p->Value + ); + } + else { + Status = STATUS_SUCCESS; + } + } + SmpRestoreDaclDefaulted( &ObjectAttributes, OriginalSdControl ); + + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Unable to create %wZ => %wZ symbolic link object - Status == 0x%lx\n", + &p->Name, + &p->Value, + Status + )); + return( Status ); + } + + NtClose( LinkHandle ); + RtlFreeHeap( RtlProcessHeap(), 0, p ); + } + + return( Status ); +} + + +VOID +SmpProcessModuleImports( + IN PVOID Parameter, + IN PCHAR ModuleName + ) +{ + NTSTATUS Status; + WCHAR NameBuffer[ DOS_MAX_PATH_LENGTH ]; + UNICODE_STRING UnicodeString; + ANSI_STRING AnsiString; + PWSTR Name, Value; + ULONG n; + PWSTR s; + PSMP_REGISTRY_VALUE p; + + // + // Skip NTDLL.DLL as it is implicitly added to KnownDll list by kernel + // before SMSS.EXE is started. + // + if (!_stricmp( ModuleName, "ntdll.dll" )) { + return; + } + + RtlInitAnsiString( &AnsiString, ModuleName ); + UnicodeString.Buffer = NameBuffer; + UnicodeString.Length = 0; + UnicodeString.MaximumLength = sizeof( NameBuffer ); + + Status = RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, FALSE ); + if (!NT_SUCCESS( Status )) { + return; + } + UnicodeString.MaximumLength = (USHORT)(UnicodeString.Length + sizeof( UNICODE_NULL )); + + s = UnicodeString.Buffer; + n = 0; + while (n < UnicodeString.Length) { + if (*s == L'.') { + break; + } + else { + n += sizeof( WCHAR ); + s += 1; + } + } + + Value = UnicodeString.Buffer; + Name = UnicodeString.Buffer + (UnicodeString.MaximumLength / sizeof( WCHAR )); + n = n / sizeof( WCHAR ); + wcsncpy( Name, Value, n ); + Name[ n ] = UNICODE_NULL; + + Status = SmpSaveRegistryValue( (PLIST_ENTRY)&SmpKnownDllsList, + Name, + Value, + TRUE + ); + if (Status == STATUS_OBJECT_NAME_EXISTS || !NT_SUCCESS( Status )) { + return; + } + + p = CONTAINING_RECORD( (PLIST_ENTRY)Parameter, + SMP_REGISTRY_VALUE, + Entry + ); + KdPrint(( "SMSS: %wZ added %ws to KnownDlls\n", &p->Value, Value )); + + return; +} + + +NTSTATUS +SmpInitializeKnownDlls( VOID ) +{ + NTSTATUS Status; + PLIST_ENTRY Head, Next; + PSMP_REGISTRY_VALUE p; + PSMP_REGISTRY_VALUE pExclude; + UNICODE_STRING UnicodeString; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE LinkHandle, FileHandle, SectionHandle; + IO_STATUS_BLOCK IoStatusBlock; + UNICODE_STRING FileName; + SECURITY_DESCRIPTOR_CONTROL OriginalSdControl; + USHORT ImageCharacteristics; + + // + // Create \KnownDlls object directory + // + + RtlInitUnicodeString( &UnicodeString, L"\\KnownDlls" ); + InitializeObjectAttributes( &ObjectAttributes, + &UnicodeString, + OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT, + NULL, + SmpKnownDllsSecurityDescriptor + ); + Status = NtCreateDirectoryObject( &SmpKnownDllObjectDirectory, + DIRECTORY_ALL_ACCESS, + &ObjectAttributes + ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Unable to create %wZ directory - Status == %lx\n", &UnicodeString, Status )); + return( Status ); + } + + // + // Open a handle to the file system directory that contains all the + // known DLL files so we can do relative opens. + // + + if (!RtlDosPathNameToNtPathName_U( SmpKnownDllPath.Buffer, + &FileName, + NULL, + NULL + ) + ) { + KdPrint(( "SMSS: Unable to to convert %wZ to an Nt path\n", &SmpKnownDllPath )); + return( STATUS_OBJECT_NAME_INVALID ); + } + + InitializeObjectAttributes( &ObjectAttributes, + &FileName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + // + // Open a handle to the known dll file directory. Don't allow + // deletes of the directory. + // + + Status = NtOpenFile( &SmpKnownDllFileDirectory, + FILE_LIST_DIRECTORY | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ); + + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Unable to open a handle to the KnownDll directory (%wZ) - Status == %lx\n", + &SmpKnownDllPath, Status + )); + return Status; + } + + RtlInitUnicodeString( &UnicodeString, L"KnownDllPath" ); + InitializeObjectAttributes( &ObjectAttributes, + &UnicodeString, + OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT, + SmpKnownDllObjectDirectory, + SmpPrimarySecurityDescriptor + ); + SmpSetDaclDefaulted( &ObjectAttributes, &OriginalSdControl ); //Use inheritable protection if available + Status = NtCreateSymbolicLinkObject( &LinkHandle, + SYMBOLIC_LINK_ALL_ACCESS, + &ObjectAttributes, + &SmpKnownDllPath + ); + SmpRestoreDaclDefaulted( &ObjectAttributes, OriginalSdControl ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Unable to create %wZ symbolic link - Status == %lx\n", + &UnicodeString, Status + )); + return( Status ); + } + + Head = &SmpKnownDllsList; + Next = Head->Flink; + while (Next != Head) { + HANDLE ObjectDirectory; + + ObjectDirectory = NULL; + p = CONTAINING_RECORD( Next, + SMP_REGISTRY_VALUE, + Entry + ); + pExclude = SmpFindRegistryValue( &SmpExcludeKnownDllsList, p->Name.Buffer ); + if (pExclude == NULL) { + pExclude = SmpFindRegistryValue( &SmpExcludeKnownDllsList, p->Value.Buffer ); + } + + if (pExclude != NULL) { + KdPrint(( "Excluding %wZ from KnownDlls\n", &p->Value )); + Status = STATUS_OBJECT_NAME_NOT_FOUND; + } + else { +#ifdef SMP_SHOW_REGISTRY_DATA + DbgPrint( "SMSS: KnownDll( %wZ = %wZ )\n", &p->Name, &p->Value ); +#endif + InitializeObjectAttributes( &ObjectAttributes, + &p->Value, + OBJ_CASE_INSENSITIVE, + SmpKnownDllFileDirectory, + NULL + ); + + Status = NtOpenFile( &FileHandle, + SYNCHRONIZE | FILE_EXECUTE, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_DELETE, + FILE_NON_DIRECTORY_FILE | FILE_SYNCHRONOUS_IO_NONALERT + ); + } + + if (NT_SUCCESS( Status )) { + ObjectDirectory = SmpKnownDllObjectDirectory; + Status = LdrVerifyImageMatchesChecksum(FileHandle, + SmpProcessModuleImports, + Next, + &ImageCharacteristics + ); + if ( Status == STATUS_IMAGE_CHECKSUM_MISMATCH ) { + + ULONG ErrorParameters; + ULONG ErrorResponse; + + // + // Hard error time. One of the know DLL's is corrupt ! + // + + ErrorParameters = (ULONG)(&p->Value); + + NtRaiseHardError( + Status, + 1, + 1, + &ErrorParameters, + OptionOk, + &ErrorResponse + ); + } + else + if (ImageCharacteristics & IMAGE_FILE_DLL) { + InitializeObjectAttributes( &ObjectAttributes, + &p->Value, + OBJ_CASE_INSENSITIVE | OBJ_PERMANENT, + ObjectDirectory, + SmpLiberalSecurityDescriptor + ); + SmpSetDaclDefaulted( &ObjectAttributes, &OriginalSdControl ); //use inheritable protection if available + Status = NtCreateSection( &SectionHandle, + SECTION_ALL_ACCESS, + &ObjectAttributes, + NULL, + PAGE_EXECUTE, + SEC_IMAGE, + FileHandle + ); + SmpRestoreDaclDefaulted( &ObjectAttributes, OriginalSdControl ); + if (!NT_SUCCESS( Status )) { + KdPrint(("SMSS: CreateSection for KnownDll %wZ failed - Status == %lx\n", + &p->Value, + Status + )); + } + else { + NtClose(SectionHandle); + } + } + else { + KdPrint(( "SMSS: Ignoring %wZ as KnownDll since it is not a DLL\n", &p->Value )); + } + + NtClose( FileHandle ); + } + + Next = Next->Flink; + + // + // Note that section remains open. This will keep it around. + // Maybe this should be a permenent section ? + // + } + + Head = &SmpKnownDllsList; + Next = Head->Flink; + while (Next != Head) { + p = CONTAINING_RECORD( Next, + SMP_REGISTRY_VALUE, + Entry + ); + Next = Next->Flink; + RtlFreeHeap( RtlProcessHeap(), 0, p ); + } +} + + +VOID +SmpProcessFileRenames( VOID ) +{ + NTSTATUS Status; + PLIST_ENTRY Head, Next; + PSMP_REGISTRY_VALUE p; + OBJECT_ATTRIBUTES ObjectAttributes; + IO_STATUS_BLOCK IoStatusBlock; + HANDLE OldFileHandle; + PFILE_RENAME_INFORMATION RenameInformation; + FILE_DISPOSITION_INFORMATION DeleteInformation; + FILE_INFORMATION_CLASS SetInfoClass; + ULONG SetInfoLength; + PVOID SetInfoBuffer; + PWSTR s; + BOOLEAN WasEnabled; + + Status = RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE, + TRUE, + FALSE, + &WasEnabled + ); + if (!NT_SUCCESS( Status )) { + WasEnabled = TRUE; + } + + // + // Process the list of file rename operations. + // + + Head = &SmpFileRenameList; + while (!IsListEmpty( Head )) { + Next = RemoveHeadList( Head ); + p = CONTAINING_RECORD( Next, + SMP_REGISTRY_VALUE, + Entry + ); +#ifdef SMP_SHOW_REGISTRY_DATA + DbgPrint( "SMSS: FileRename( %wZ => %wZ )\n", &p->Name, &p->Value ); +#endif + InitializeObjectAttributes( + &ObjectAttributes, + &p->Name, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + // + // Open the file for delete access + // + + Status = NtOpenFile( &OldFileHandle, + (ACCESS_MASK)DELETE | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT + ); + if (NT_SUCCESS( Status )) { + if (p->Value.Length == 0) { + SetInfoClass = FileDispositionInformation; + SetInfoLength = sizeof( DeleteInformation ); + SetInfoBuffer = &DeleteInformation; + DeleteInformation.DeleteFile = TRUE; + RenameInformation = NULL; + } + else { + SetInfoClass = FileRenameInformation; + SetInfoLength = p->Value.Length + + sizeof( *RenameInformation ); + s = p->Value.Buffer; + if (*s == L'!') { + s++; + SetInfoLength -= sizeof( UNICODE_NULL ); + } + + SetInfoBuffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), + SetInfoLength + ); + + if (SetInfoBuffer != NULL) { + RenameInformation = SetInfoBuffer; + RenameInformation->ReplaceIfExists = (BOOLEAN)(s != p->Value.Buffer); + RenameInformation->RootDirectory = NULL; + RenameInformation->FileNameLength = SetInfoLength - sizeof( *RenameInformation ); + RtlMoveMemory( RenameInformation->FileName, + s, + RenameInformation->FileNameLength + ); + } + else { + Status = STATUS_NO_MEMORY; + } + } + + if (NT_SUCCESS( Status )) { + Status = NtSetInformationFile( OldFileHandle, + &IoStatusBlock, + SetInfoBuffer, + SetInfoLength, + SetInfoClass + ); + } + + NtClose( OldFileHandle ); + } + +#if DBG + if (!NT_SUCCESS( Status )) { + DbgPrint( "SM: %wZ => %wZ failed - Status == %x\n", + &p->Name, &p->Value, Status + ); + } + else + if (p->Value.Length == 0) { + DbgPrint( "SM: %wZ (deleted)\n", &p->Name ); + } + else { + DbgPrint( "SM: %wZ (renamed to) %wZ\n", &p->Name, &p->Value ); + } +#endif + + RtlFreeHeap( RtlProcessHeap(), 0, p ); + } + + if (!WasEnabled) { + Status = RtlAdjustPrivilege( SE_RESTORE_PRIVILEGE, + FALSE, + FALSE, + &WasEnabled + ); + } + + return; +} + + +#ifdef SMP_SHOW_REGISTRY_DATA +VOID +SmpDumpQuery( + IN PCHAR RoutineName, + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength + ) +{ + PWSTR s; + + if (ValueName == NULL) { + DbgPrint( "SM: SmpConfigure%s( %ws )\n", RoutineName ); + return; + } + + if (ValueData == NULL) { + DbgPrint( "SM: SmpConfigure%s( %ws, %ws NULL ValueData )\n", RoutineName, ValueName ); + return; + } + + s = (PWSTR)ValueData; + DbgPrint( "SM: SmpConfigure%s( %ws, %u, (%u) ", RoutineName, ValueName, ValueType, ValueLength ); + if (ValueType == REG_SZ || ValueType == REG_EXPAND_SZ || ValueType == REG_MULTI_SZ) { + while (*s) { + if (s != (PWSTR)ValueData) { + DbgPrint( ", " ); + } + DbgPrint( "'%ws'", s ); + while(*s++) { + } + if (ValueType != REG_MULTI_SZ) { + break; + } + } + } + else { + DbgPrint( "*** non-string data (%08lx)", *(PULONG)ValueData ); + } + + DbgPrint( "\n" ); +} +#endif + +NTSTATUS +SmpConfigureObjectDirectories( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) +{ + PWSTR s; + UNICODE_STRING UnicodeString; + UNICODE_STRING RpcControl; + UNICODE_STRING Windows; + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE DirectoryHandle; + PSECURITY_DESCRIPTOR SecurityDescriptor; + + UNREFERENCED_PARAMETER( Context ); + + RtlInitUnicodeString( &RpcControl, L"\\RPC Control"); + RtlInitUnicodeString( &Windows, L"\\Windows"); +#ifdef SMP_SHOW_REGISTRY_DATA + SmpDumpQuery( "ObjectDirectories", ValueName, ValueType, ValueData, ValueLength ); +#else + UNREFERENCED_PARAMETER( ValueName ); + UNREFERENCED_PARAMETER( ValueType ); + UNREFERENCED_PARAMETER( ValueLength ); +#endif + s = (PWSTR)ValueData; + while (*s) { + RtlInitUnicodeString( &UnicodeString, s ); + + // + // This is NOT how I would choose to do this if starting from + // scratch, but we are very close to shipping Daytona and I + // needed to get the right protection on these objects. + // + + SecurityDescriptor = SmpPrimarySecurityDescriptor; + if (RtlEqualString( (PSTRING)&UnicodeString, (PSTRING)&RpcControl, TRUE ) || + RtlEqualString( (PSTRING)&UnicodeString, (PSTRING)&Windows, TRUE) ) { + SecurityDescriptor = SmpLiberalSecurityDescriptor; + } + + InitializeObjectAttributes( &ObjectAttributes, + &UnicodeString, + OBJ_CASE_INSENSITIVE | OBJ_OPENIF | OBJ_PERMANENT, + NULL, + SecurityDescriptor + ); + Status = NtCreateDirectoryObject( &DirectoryHandle, + DIRECTORY_ALL_ACCESS, + &ObjectAttributes + ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Unable to create %wZ object directory - Status == %lx\n", &UnicodeString, Status )); + } + else { + NtClose( DirectoryHandle ); + } + + while (*s++) { + } + } + + // + // We dont care if the creates failed. + // + + return( STATUS_SUCCESS ); +} + +NTSTATUS +SmpConfigureExecute( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) +{ + UNREFERENCED_PARAMETER( Context ); + +#ifdef SMP_SHOW_REGISTRY_DATA + SmpDumpQuery( "Execute", ValueName, ValueType, ValueData, ValueLength ); +#else + UNREFERENCED_PARAMETER( ValueName ); + UNREFERENCED_PARAMETER( ValueType ); + UNREFERENCED_PARAMETER( ValueLength ); +#endif + return (SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext, + ValueData, + NULL, + TRUE + ) + ); +} + +NTSTATUS +SmpConfigureMemoryMgmt( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) +{ + NTSTATUS Status = STATUS_SUCCESS; + UNREFERENCED_PARAMETER( Context ); + +#ifdef SMP_SHOW_REGISTRY_DATA + SmpDumpQuery( "MemoryMgmt", ValueName, ValueType, ValueData, ValueLength ); +#else + UNREFERENCED_PARAMETER( ValueName ); + UNREFERENCED_PARAMETER( ValueType ); + UNREFERENCED_PARAMETER( ValueLength ); +#endif + return (SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext, + ValueData, + NULL, + TRUE + ) + ); +} + +NTSTATUS +SmpConfigureFileRenames( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) +{ + NTSTATUS Status; + static PWSTR OldName = NULL; + + UNREFERENCED_PARAMETER( Context ); +#ifdef SMP_SHOW_REGISTRY_DATA + SmpDumpQuery( "FileRenameOperation", ValueName, ValueType, ValueData, ValueLength ); +#else + UNREFERENCED_PARAMETER( ValueType ); +#endif + + // + // This routine gets called for each string in the MULTI_SZ. The + // first string we get is the old name, the next string is the new name. + // + if (OldName == NULL) { + // + // Save a pointer to the old name, we'll need it on the next + // callback. + // + OldName = ValueData; + return(STATUS_SUCCESS); + } else { + Status = SmpSaveRegistryValue((PLIST_ENTRY)EntryContext, + OldName, + ValueData, + FALSE); + if (!NT_SUCCESS(Status)) { +#ifdef SMP_SHOW_REGISTRY_DATA + DbgPrint("SMSS: SmpSaveRegistryValue returned %08lx for FileRenameOperation\n", Status); + DbgPrint("SMSS: %ws %ws\n", OldName, ValueData); +#endif + } + OldName = NULL; + return(Status); + } +} + +NTSTATUS +SmpConfigureDosDevices( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) +{ + UNREFERENCED_PARAMETER( Context ); + +#ifdef SMP_SHOW_REGISTRY_DATA + SmpDumpQuery( "DosDevices", ValueName, ValueType, ValueData, ValueLength ); +#else + UNREFERENCED_PARAMETER( ValueType ); + UNREFERENCED_PARAMETER( ValueLength ); +#endif + return (SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext, + ValueName, + ValueData, + TRUE + ) + ); +} + +NTSTATUS +SmpConfigureKnownDlls( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) +{ + UNREFERENCED_PARAMETER( Context ); + +#ifdef SMP_SHOW_REGISTRY_DATA + SmpDumpQuery( "KnownDlls", ValueName, ValueType, ValueData, ValueLength ); +#else + UNREFERENCED_PARAMETER( ValueType ); +#endif + if (!_wcsicmp( ValueName, L"DllDirectory" )) { + SmpKnownDllPath.Buffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), + ValueLength + ); + if (SmpKnownDllPath.Buffer == NULL) { + return( STATUS_NO_MEMORY ); + } + + SmpKnownDllPath.Length = (USHORT)(ValueLength - sizeof( UNICODE_NULL ) ); + SmpKnownDllPath.MaximumLength = (USHORT)ValueLength; + RtlMoveMemory( SmpKnownDllPath.Buffer, + ValueData, + ValueLength + ); + return( STATUS_SUCCESS ); + } + else { + return (SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext, + ValueName, + ValueData, + TRUE + ) + ); + } +} + +NTSTATUS +SmpConfigureExcludeKnownDlls( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) +{ + NTSTATUS Status; + UNREFERENCED_PARAMETER( Context ); + +#ifdef SMP_SHOW_REGISTRY_DATA + SmpDumpQuery( "ExcludeKnownDlls", ValueName, ValueType, ValueData, ValueLength ); +#else + UNREFERENCED_PARAMETER( ValueType ); +#endif + if (ValueType == REG_MULTI_SZ || ValueType == REG_SZ) { + PWSTR s; + + s = (PWSTR)ValueData; + while (*s != UNICODE_NULL) { + Status = SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext, + s, + NULL, + TRUE + ); + if (!NT_SUCCESS( Status ) || ValueType == REG_SZ) { + return Status; + } + + while (*s++ != UNICODE_NULL) { + } + } + } + + return( STATUS_SUCCESS ); +} + +NTSTATUS +SmpConfigureEnvironment( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) +{ + NTSTATUS Status; + UNICODE_STRING Name, Value; + UNREFERENCED_PARAMETER( Context ); + UNREFERENCED_PARAMETER( EntryContext ); + +#ifdef SMP_SHOW_REGISTRY_DATA + SmpDumpQuery( "Environment", ValueName, ValueType, ValueData, ValueLength ); +#else + UNREFERENCED_PARAMETER( ValueType ); +#endif + + + RtlInitUnicodeString( &Name, ValueName ); + RtlInitUnicodeString( &Value, ValueData ); + + Status = RtlSetEnvironmentVariable( NULL, + &Name, + &Value + ); + + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: 'SET %wZ = %wZ' failed - Status == %lx\n", + &Name, &Value, Status + )); + return( Status ); + } + + if (!_wcsicmp( ValueName, L"Path" )) { + + SmpDefaultLibPathBuffer = RtlAllocateHeap( + RtlProcessHeap(), + MAKE_TAG( INIT_TAG ), + ValueLength + ); + if ( !SmpDefaultLibPathBuffer ) { + return ( STATUS_NO_MEMORY ); + } + + RtlMoveMemory( SmpDefaultLibPathBuffer, + ValueData, + ValueLength + ); + + RtlInitUnicodeString( &SmpDefaultLibPath, SmpDefaultLibPathBuffer ); + } + + return( STATUS_SUCCESS ); +} + +NTSTATUS +SmpConfigureSubSystems( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) +{ + + UNREFERENCED_PARAMETER( Context ); + +#ifdef SMP_SHOW_REGISTRY_DATA + SmpDumpQuery( "SubSystems", ValueName, ValueType, ValueData, ValueLength ); +#else + UNREFERENCED_PARAMETER( ValueLength ); +#endif + + if (!_wcsicmp( ValueName, L"Required" ) || !_wcsicmp( ValueName, L"Optional" )) { + if (ValueType == REG_MULTI_SZ) { + // + // Here if processing Required= or Optional= values, since they are + // the only REG_MULTI_SZ value types under the SubSystem key. + // + PSMP_REGISTRY_VALUE p; + PWSTR s; + + s = (PWSTR)ValueData; + while (*s != UNICODE_NULL) { + p = SmpFindRegistryValue( (PLIST_ENTRY)EntryContext, + s + ); + if (p != NULL) { + RemoveEntryList( &p->Entry ); + + + // + // Required Subsystems are loaded. Optional subsystems are + // defered. + // + + if (!_wcsicmp( ValueName, L"Required" ) ) { + InsertTailList( &SmpSubSystemsToLoad, &p->Entry ); + } + else { + InsertTailList( &SmpSubSystemsToDefer, &p->Entry ); + } + } + else { + KdPrint(( "SMSS: Invalid subsystem name - %ws\n", s )); + } + + while (*s++ != UNICODE_NULL) { + } + } + } + + return( STATUS_SUCCESS ); + } + else { + return (SmpSaveRegistryValue( (PLIST_ENTRY)EntryContext, + ValueName, + ValueData, + TRUE + ) + ); + } +} + + +NTSTATUS +SmpParseToken( + IN PUNICODE_STRING Source, + IN BOOLEAN RemainderOfSource, + OUT PUNICODE_STRING Token + ) +{ + PWSTR s, s1; + ULONG i, cb; + + RtlInitUnicodeString( Token, NULL ); + s = Source->Buffer; + if (Source->Length == 0) { + return( STATUS_SUCCESS ); + } + + i = 0; + while ((USHORT)i < Source->Length && *s <= L' ') { + s++; + i += 2; + } + if (RemainderOfSource) { + cb = Source->Length - (i * sizeof( WCHAR )); + s1 = (PWSTR)((PCHAR)s + cb); + i = Source->Length / sizeof( WCHAR ); + } + else { + s1 = s; + while ((USHORT)i < Source->Length && *s1 > L' ') { + s1++; + i += 2; + } + cb = (PCHAR)s1 - (PCHAR)s; + while ((USHORT)i < Source->Length && *s1 <= L' ') { + s1++; + i += 2; + } + } + + if (cb > 0) { + Token->Buffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), cb + sizeof( UNICODE_NULL ) ); + if (Token->Buffer == NULL) { + return( STATUS_NO_MEMORY ); + } + + Token->Length = (USHORT)cb; + Token->MaximumLength = (USHORT)(cb + sizeof( UNICODE_NULL )); + RtlMoveMemory( Token->Buffer, s, cb ); + Token->Buffer[ cb / sizeof( WCHAR ) ] = UNICODE_NULL; + } + + Source->Length -= (USHORT)((PCHAR)s1 - (PCHAR)Source->Buffer); + Source->Buffer = s1; + return( STATUS_SUCCESS ); +} + + +NTSTATUS +SmpParseCommandLine( + IN PUNICODE_STRING CommandLine, + OUT PULONG Flags OPTIONAL, + OUT PUNICODE_STRING ImageFileName, + OUT PUNICODE_STRING ImageFileDirectory, + OUT PUNICODE_STRING Arguments + ) +{ + NTSTATUS Status; + UNICODE_STRING Input, Token; + UNICODE_STRING PathVariableName; + UNICODE_STRING PathVariableValue; + PWSTR DosFilePart; + WCHAR FullDosPathBuffer[ DOS_MAX_PATH_LENGTH ]; + ULONG SpResult; + + RtlInitUnicodeString( ImageFileName, NULL ); + RtlInitUnicodeString( Arguments, NULL ); + + // + // make sure lib path has systemroot\system32. Otherwise, the system will + // not boot properly + // + + if ( !SmpSystemRoot.Length ) { + UNICODE_STRING NewLibString; + + RtlInitUnicodeString( &SmpSystemRoot,USER_SHARED_DATA->NtSystemRoot ); + + + NewLibString.Length = 0; + NewLibString.MaximumLength = + SmpSystemRoot.MaximumLength + + 20 + // length of \system32; + SmpDefaultLibPath.MaximumLength; + + NewLibString.Buffer = RtlAllocateHeap( + RtlProcessHeap(), + MAKE_TAG( INIT_TAG ), + NewLibString.MaximumLength + ); + + if ( NewLibString.Buffer ) { + RtlAppendUnicodeStringToString(&NewLibString,&SmpSystemRoot ); + RtlAppendUnicodeToString(&NewLibString,L"\\system32;"); + RtlAppendUnicodeStringToString(&NewLibString,&SmpDefaultLibPath ); + + RtlFreeHeap(RtlProcessHeap(), 0, SmpDefaultLibPath.Buffer ); + + SmpDefaultLibPath = NewLibString; + } + } + + Input = *CommandLine; + while (TRUE) { + Status = SmpParseToken( &Input, FALSE, &Token ); + if (!NT_SUCCESS( Status ) || Token.Buffer == NULL) { + return( STATUS_UNSUCCESSFUL ); + } + + if (ARGUMENT_PRESENT( Flags )) { + if (RtlEqualUnicodeString( &Token, &SmpDebugKeyword, TRUE )) { + *Flags |= SMP_DEBUG_FLAG; + RtlFreeHeap( RtlProcessHeap(), 0, Token.Buffer ); + continue; + } + else + if (RtlEqualUnicodeString( &Token, &SmpASyncKeyword, TRUE )) { + *Flags |= SMP_ASYNC_FLAG; + RtlFreeHeap( RtlProcessHeap(), 0, Token.Buffer ); + continue; + } + else + if (RtlEqualUnicodeString( &Token, &SmpAutoChkKeyword, TRUE )) { + *Flags |= SMP_AUTOCHK_FLAG; + RtlFreeHeap( RtlProcessHeap(), 0, Token.Buffer ); + continue; + } + } + + SpResult = 0; + RtlInitUnicodeString( &PathVariableName, L"Path" ); + PathVariableValue.Length = 0; + PathVariableValue.MaximumLength = 4096; + PathVariableValue.Buffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), + PathVariableValue.MaximumLength + ); + Status = RtlQueryEnvironmentVariable_U( SmpDefaultEnvironment, + &PathVariableName, + &PathVariableValue + ); + if ( Status == STATUS_BUFFER_TOO_SMALL ) { + PathVariableValue.MaximumLength = PathVariableValue.Length + 2; + PathVariableValue.Length = 0; + PathVariableValue.Buffer = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), + PathVariableValue.MaximumLength + ); + Status = RtlQueryEnvironmentVariable_U( SmpDefaultEnvironment, + &PathVariableName, + &PathVariableValue + ); + } + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: %wZ environment variable not defined.\n", &PathVariableName )); + Status = STATUS_OBJECT_NAME_NOT_FOUND; + } + else + if (!ARGUMENT_PRESENT( Flags ) || + !(SpResult = RtlDosSearchPath_U( PathVariableValue.Buffer, + Token.Buffer, + L".exe", + sizeof( FullDosPathBuffer ), + FullDosPathBuffer, + &DosFilePart + )) + ) { + if (!ARGUMENT_PRESENT( Flags )) { + wcscpy( FullDosPathBuffer, Token.Buffer ); + } + else { + + if ( !SpResult ) { + + // + // The search path call failed. Now try the call again using + // the default lib path. This always has systemroot\system32 + // at the front. + // + + SpResult = RtlDosSearchPath_U( + SmpDefaultLibPath.Buffer, + Token.Buffer, + L".exe", + sizeof( FullDosPathBuffer ), + FullDosPathBuffer, + &DosFilePart + ); + } + if ( !SpResult ) { + *Flags |= SMP_IMAGE_NOT_FOUND; + *ImageFileName = Token; + RtlFreeHeap( RtlProcessHeap(), 0, PathVariableValue.Buffer ); + return( STATUS_SUCCESS ); + } + } + } + + RtlFreeHeap( RtlProcessHeap(), 0, PathVariableValue.Buffer ); + if (NT_SUCCESS( Status ) && + !RtlDosPathNameToNtPathName_U( FullDosPathBuffer, + ImageFileName, + NULL, + NULL + ) + ) { + KdPrint(( "SMSS: Unable to translate %ws into an NT File Name\n", + FullDosPathBuffer + )); + Status = STATUS_OBJECT_PATH_INVALID; + } + + if (!NT_SUCCESS( Status )) { + return( Status ); + } + + if (ARGUMENT_PRESENT( ImageFileDirectory )) { + if (DosFilePart > FullDosPathBuffer) { + *--DosFilePart = UNICODE_NULL; + RtlCreateUnicodeString( ImageFileDirectory, + FullDosPathBuffer + ); + } + else { + RtlInitUnicodeString( ImageFileDirectory, NULL ); + } + } + + break; + } + + Status = SmpParseToken( &Input, TRUE, Arguments ); + return( Status ); +} + + +ULONG +SmpConvertInteger( + IN PWSTR String + ) +{ + NTSTATUS Status; + UNICODE_STRING UnicodeString; + ULONG Value; + + RtlInitUnicodeString( &UnicodeString, String ); + Status = RtlUnicodeStringToInteger( &UnicodeString, 0, &Value ); + if (NT_SUCCESS( Status )) { + return( Value ); + } + else { + return( 0 ); + } +} + +NTSTATUS +SmpAddPagingFile( + IN PUNICODE_STRING PagingFileSpec + ) + +/*++ + +Routine Description: + + This function is called during configuration to add a paging file + to the system. + + The format of PagingFileSpec is: + + name-of-paging-file size-of-paging-file(in megabytes) + +Arguments: + + PagingFileSpec - Unicode string that specifies the paging file name + and size. + +Return Value: + + Status of operation + +--*/ + +{ + NTSTATUS Status; + UNICODE_STRING PagingFileName; + UNICODE_STRING Arguments; + ULONG PageFileMinSizeInMb; + ULONG PageFileMaxSizeInMb; + PWSTR ArgSave, Arg2; + + if (CountPageFiles == MAX_PAGING_FILES) { + KdPrint(( "SMSS: Too many paging files specified - %d\n", CountPageFiles )); + return( STATUS_TOO_MANY_PAGING_FILES ); + } + + Status = SmpParseCommandLine( PagingFileSpec, + NULL, + &PagingFileName, + NULL, + &Arguments + ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: SmpParseCommand( %wZ ) failed - Status == %lx\n", PagingFileSpec, Status )); + return( Status ); + } + + PageFileMaxSizeInMb = 0; + Status = RtlUnicodeStringToInteger( &Arguments, 0, &PageFileMinSizeInMb ); + if (!NT_SUCCESS( Status )) { + PageFileMinSizeInMb = 10; + } + else { + ArgSave = Arguments.Buffer; + Arg2 = ArgSave; + while (*Arg2 != UNICODE_NULL) { + if (*Arg2++ == L' ') { + Arguments.Length -= (USHORT)((PCHAR)Arg2 - (PCHAR)ArgSave); + Arguments.Buffer = Arg2; + Status = RtlUnicodeStringToInteger( &Arguments, 0, &PageFileMaxSizeInMb ); + if (!NT_SUCCESS( Status )) { + PageFileMaxSizeInMb = 0; + } + + Arguments.Buffer = ArgSave; + break; + } + } + } + + if (PageFileMinSizeInMb == 0) { + PageFileMinSizeInMb = 10; + } + + if (PageFileMaxSizeInMb == 0) { + PageFileMaxSizeInMb = PageFileMinSizeInMb + 50; + } + else + if (PageFileMaxSizeInMb < PageFileMinSizeInMb) { + PageFileMaxSizeInMb = PageFileMinSizeInMb; + } + + PageFileSpecs[ CountPageFiles ] = PagingFileName; + PageFileMinSizes[ CountPageFiles ] = (LONG)PageFileMinSizeInMb; + PageFileMaxSizes[ CountPageFiles ] = (LONG)PageFileMaxSizeInMb; + + CountPageFiles++; + + if (Arguments.Buffer) { + RtlFreeHeap( RtlProcessHeap(), 0, Arguments.Buffer ); + } + + return STATUS_SUCCESS; +} + + +NTSTATUS +SmpCreatePagingFile( + PUNICODE_STRING PageFileSpec, + LARGE_INTEGER MinPagingFileSize, + LARGE_INTEGER MaxPagingFileSize + ) +{ + NTSTATUS Status, Status1; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE Handle; + IO_STATUS_BLOCK IoStatusBlock; + BOOLEAN FileSizeInfoValid; + FILE_STANDARD_INFORMATION FileSizeInfo; + FILE_DISPOSITION_INFORMATION Disposition; + FILE_FS_SIZE_INFORMATION SizeInfo; + UNICODE_STRING VolumePath; + ULONG n; + PWSTR s; + LARGE_INTEGER AvailableBytes; + LARGE_INTEGER MinimumSlop; + + FileSizeInfoValid = FALSE; + InitializeObjectAttributes( &ObjectAttributes, + PageFileSpec, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + Status = NtOpenFile( &Handle, + (ACCESS_MASK)FILE_READ_ATTRIBUTES | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT + ); + if (NT_SUCCESS( Status )) { + Status = NtQueryInformationFile( Handle, + &IoStatusBlock, + &FileSizeInfo, + sizeof( FileSizeInfo ), + FileStandardInformation + ); + + if (NT_SUCCESS( Status )) { + FileSizeInfoValid = TRUE; + } + + NtClose( Handle ); + } + + VolumePath = *PageFileSpec; + n = VolumePath.Length; + VolumePath.Length = 0; + s = VolumePath.Buffer; + while (n) { + if (*s++ == L':' && *s == OBJ_NAME_PATH_SEPARATOR) { + s++; + break; + } + else { + n -= sizeof( WCHAR ); + } + } + VolumePath.Length = (USHORT)((PCHAR)s - (PCHAR)VolumePath.Buffer); + InitializeObjectAttributes( &ObjectAttributes, + &VolumePath, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + Status = NtOpenFile( &Handle, + (ACCESS_MASK)FILE_LIST_DIRECTORY | SYNCHRONIZE, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_READ | FILE_SHARE_WRITE, + FILE_SYNCHRONOUS_IO_NONALERT | FILE_DIRECTORY_FILE + ); + if (!NT_SUCCESS( Status )) { + return Status; + } + + // + // Determine the size parameters of the volume. + // + + Status = NtQueryVolumeInformationFile( Handle, + &IoStatusBlock, + &SizeInfo, + sizeof( SizeInfo ), + FileFsSizeInformation + ); + NtClose( Handle ); + if (!NT_SUCCESS( Status )) { + return Status; + } + + + // + // Deal with 64 bit sizes + // + + AvailableBytes = RtlExtendedIntegerMultiply( SizeInfo.AvailableAllocationUnits, + SizeInfo.SectorsPerAllocationUnit + ); + + AvailableBytes = RtlExtendedIntegerMultiply( AvailableBytes, + SizeInfo.BytesPerSector + ); + if (FileSizeInfoValid) { + AvailableBytes.QuadPart += FileSizeInfo.AllocationSize.QuadPart; + } + + if ( AvailableBytes.QuadPart <= MinPagingFileSize.QuadPart ) { + Status = STATUS_DISK_FULL; + } + else { + AvailableBytes.QuadPart -= ( 2 * 1024 * 1024 ); + if ( AvailableBytes.QuadPart <= MinPagingFileSize.QuadPart ) { + Status = STATUS_DISK_FULL; + } + else { + Status = STATUS_SUCCESS; + } + } + + + if (NT_SUCCESS( Status )) { + Status = NtCreatePagingFile( PageFileSpec, + &MinPagingFileSize, + &MaxPagingFileSize, + 0 + ); + } + else + if (FileSizeInfoValid) { + InitializeObjectAttributes( &ObjectAttributes, + PageFileSpec, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + Status1 = NtOpenFile( &Handle, + (ACCESS_MASK)DELETE, + &ObjectAttributes, + &IoStatusBlock, + FILE_SHARE_DELETE | + FILE_SHARE_READ | + FILE_SHARE_WRITE, + FILE_NON_DIRECTORY_FILE + ); + if (NT_SUCCESS( Status1 )) { + Disposition.DeleteFile = TRUE; + Status1 = NtSetInformationFile( Handle, + &IoStatusBlock, + &Disposition, + sizeof( Disposition ), + FileDispositionInformation + ); + + if (NT_SUCCESS( Status1 )) { + KdPrint(( "SMSS: Deleted stale paging file - %wZ\n", PageFileSpec )); + } + + NtClose(Handle); + } + } + + return Status; +} + + +NTSTATUS +SmpCreatePagingFiles( VOID ) +{ + LARGE_INTEGER MinPagingFileSize, MaxPagingFileSize; + NTSTATUS Status; + ULONG i, Pass; + PWSTR CurrentDrive; + char MessageBuffer[ 128 ]; + BOOLEAN CreatedAtLeastOnePagingFile = FALSE; + + Status = STATUS_SUCCESS; + for (Pass=1; Pass<=2; Pass++) { + for (i=0; i<CountPageFiles; i++) { + if (CurrentDrive = wcsstr( PageFileSpecs[ i ].Buffer, L"?:" )) { + if (Pass == 2 && CreatedAtLeastOnePagingFile) { + continue; + } + + *CurrentDrive = L'C'; + } + else + if (Pass == 2) { + continue; + } +retry: + MinPagingFileSize.QuadPart = Int32x32To64( PageFileMinSizes[ i ], + 0x100000 + ); + MaxPagingFileSize.QuadPart = Int32x32To64( PageFileMaxSizes[ i ], + 0x100000 + ); + Status = SmpCreatePagingFile( &PageFileSpecs[ i ], + MinPagingFileSize, + MaxPagingFileSize + ); + if (!NT_SUCCESS( Status )) { + if (CurrentDrive && + Pass == 1 && + *CurrentDrive < L'Z' && + Status != STATUS_NO_SUCH_DEVICE && + Status != STATUS_OBJECT_PATH_NOT_FOUND && + Status != STATUS_OBJECT_NAME_NOT_FOUND + ) { + *CurrentDrive += 1; + goto retry; + } + else + if (PageFileMinSizes[ i ] > 2 && + (CurrentDrive == NULL || Pass == 2) && + Status == STATUS_DISK_FULL + ) { + PageFileMinSizes[ i ] -= 2; + goto retry; + } + else + if (CurrentDrive && + Pass == 2 && + *CurrentDrive < L'Z' && + Status == STATUS_DISK_FULL + ) { + *CurrentDrive += 1; + goto retry; + } + else + if (CurrentDrive && Pass == 2) { + *CurrentDrive = L'?'; + sprintf( MessageBuffer, + "INIT: Failed to find drive with space for %wZ (%u MB)\n", + &PageFileSpecs[ i ], + PageFileMinSizes[ i ] + ); + +#if DBG + SmpDisplayString( MessageBuffer ); +#endif + } + } + else { + CreatedAtLeastOnePagingFile = TRUE; + if (CurrentDrive) { + sprintf( MessageBuffer, + "INIT: Created paging file: %wZ [%u..%u] MB\n", + &PageFileSpecs[ i ], + PageFileMinSizes[ i ], + PageFileMaxSizes[ i ] + ); + +#if DBG + SmpDisplayString( MessageBuffer ); +#endif + } + } + + if (Pass == 2) { + RtlFreeHeap( RtlProcessHeap(), 0, PageFileSpecs[ i ].Buffer ); + } + } + } + + if (!CreatedAtLeastOnePagingFile) { + sprintf( MessageBuffer, + "INIT: Unable to create a paging file. Proceeding anyway.\n" + ); + +#if DBG + SmpDisplayString( MessageBuffer ); +#endif + } + + return( Status ); +} + + +NTSTATUS +SmpExecuteImage( + IN PUNICODE_STRING ImageFileName, + IN PUNICODE_STRING CurrentDirectory, + IN PUNICODE_STRING CommandLine, + IN ULONG Flags, + IN OUT PRTL_USER_PROCESS_INFORMATION ProcessInformation OPTIONAL + ) + +/*++ + +Routine Description: + + This function creates and starts a process specified by the + CommandLine parameter. After starting the process, the procedure + will optionally wait for the first thread in the process to + terminate. + +Arguments: + + ImageFileName - Supplies the full NT path for the image file to + execute. Presumably computed or extracted from the first + token of the CommandLine. + + CommandLine - Supplies the command line to execute. The first blank + separate token on the command line must be a fully qualified NT + Path name of an image file to execute. + + Flags - Supplies information about how to invoke the command. + + ProcessInformation - Optional parameter, which if specified, receives + information for images invoked with the SMP_ASYNC_FLAG. Ignore + if this flag is not set. + +Return Value: + + Status of operation + +--*/ + +{ + NTSTATUS Status; + RTL_USER_PROCESS_INFORMATION MyProcessInformation; + PRTL_USER_PROCESS_PARAMETERS ProcessParameters; + + if (!ARGUMENT_PRESENT( ProcessInformation )) { + ProcessInformation = &MyProcessInformation; + } + + + Status = RtlCreateProcessParameters( &ProcessParameters, + ImageFileName, + (SmpDefaultLibPath.Length == 0 ? + NULL : &SmpDefaultLibPath + ), + CurrentDirectory, + CommandLine, + SmpDefaultEnvironment, + NULL, + NULL, + NULL, + NULL + ); + ASSERTMSG( "RtlCreateProcessParameters", NT_SUCCESS( Status ) ); + if (Flags & SMP_DEBUG_FLAG) { + ProcessParameters->DebugFlags = TRUE; + } + else { + ProcessParameters->DebugFlags = SmpDebug; + } + + if ( Flags & SMP_SUBSYSTEM_FLAG ) { + ProcessParameters->Flags |= RTL_USER_PROC_RESERVE_1MB; + } + + ProcessInformation->Length = sizeof( RTL_USER_PROCESS_INFORMATION ); + Status = RtlCreateUserProcess( ImageFileName, + OBJ_CASE_INSENSITIVE, + ProcessParameters, + NULL, + NULL, + NULL, + FALSE, + NULL, + NULL, + ProcessInformation + ); + RtlDestroyProcessParameters( ProcessParameters ); + + if ( !NT_SUCCESS( Status ) ) { + KdPrint(( "SMSS: Failed load of %wZ - Status == %lx\n", + ImageFileName, + Status + )); + return( Status ); + } + + if (!(Flags & SMP_DONT_START)) { + if (ProcessInformation->ImageInformation.SubSystemType != + IMAGE_SUBSYSTEM_NATIVE + ) { + NtTerminateProcess( ProcessInformation->Process, + STATUS_INVALID_IMAGE_FORMAT + ); + NtWaitForSingleObject( ProcessInformation->Thread, FALSE, NULL ); + NtClose( ProcessInformation->Thread ); + NtClose( ProcessInformation->Process ); + KdPrint(( "SMSS: Not an NT image - %wZ\n", ImageFileName )); + return( STATUS_INVALID_IMAGE_FORMAT ); + } + + NtResumeThread( ProcessInformation->Thread, NULL ); + + if (!(Flags & SMP_ASYNC_FLAG)) { + NtWaitForSingleObject( ProcessInformation->Thread, FALSE, NULL ); + } + + NtClose( ProcessInformation->Thread ); + NtClose( ProcessInformation->Process ); + } + + return( Status ); +} + + +NTSTATUS +SmpExecuteCommand( + IN PUNICODE_STRING CommandLine, + IN ULONG Flags + ) +/*++ + +Routine Description: + + This function is called to execute a command. + + The format of CommandLine is: + + Nt-Path-To-AutoChk.exe Nt-Path-To-Disk-Partition + + If the NT path to the disk partition is an asterisk, then invoke + the AutoChk.exe utility on all hard disk partitions. + +Arguments: + + CommandLine - Supplies the Command line to invoke. + + Flags - Specifies the type of command and options. + +Return Value: + + Status of operation + +--*/ +{ + NTSTATUS Status; + UNICODE_STRING ImageFileName; + UNICODE_STRING CurrentDirectory; + UNICODE_STRING Arguments; + + if (Flags & SMP_DEBUG_FLAG) { + return( SmpLoadDbgSs( NULL ) ); + } + + Status = SmpParseCommandLine( CommandLine, + &Flags, + &ImageFileName, + &CurrentDirectory, + &Arguments + ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: SmpParseCommand( %wZ ) failed - Status == %lx\n", CommandLine, Status )); + return( Status ); + } + + if (Flags & SMP_AUTOCHK_FLAG) { + Status = SmpInvokeAutoChk( &ImageFileName, &CurrentDirectory, &Arguments, Flags ); + } + else + if (Flags & SMP_SUBSYSTEM_FLAG) { + Status = SmpLoadSubSystem( &ImageFileName, &CurrentDirectory, CommandLine, Flags ); + } + else { + if (Flags & SMP_IMAGE_NOT_FOUND) { + KdPrint(( "SMSS: Image file (%wZ) not found\n", &ImageFileName )); + Status = STATUS_OBJECT_NAME_NOT_FOUND; + } + else { + Status = SmpExecuteImage( &ImageFileName, + &CurrentDirectory, + CommandLine, + Flags, + NULL + ); + } + } + + if (ImageFileName.Buffer && !(Flags & SMP_IMAGE_NOT_FOUND)) { + RtlFreeHeap( RtlProcessHeap(), 0, ImageFileName.Buffer ); + if (CurrentDirectory.Buffer != NULL) { + RtlFreeHeap( RtlProcessHeap(), 0, CurrentDirectory.Buffer ); + } + } + + if (Arguments.Buffer) { + RtlFreeHeap( RtlProcessHeap(), 0, Arguments.Buffer ); + } + + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Command '%wZ' failed - Status == %x\n", CommandLine, Status )); + } + + return( Status ); +} + + + +NTSTATUS +SmpInvokeAutoChk( + IN PUNICODE_STRING ImageFileName, + IN PUNICODE_STRING CurrentDirectory, + IN PUNICODE_STRING Arguments, + IN ULONG Flags + ) +{ + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE Handle; + + POBJECT_DIRECTORY_INFORMATION DirInfo; + CHAR DirInfoBuffer[ 256 ]; + ULONG Context, Length; + BOOLEAN RestartScan; + BOOLEAN ForceAutoChk; + + UNICODE_STRING ArgPrefix; + UNICODE_STRING LinkTarget; + UNICODE_STRING LinkTypeName; + UNICODE_STRING LinkTargetPrefix; + WCHAR LinkTargetBuffer[ MAXIMUM_FILENAME_LENGTH ]; + + CHAR DisplayBuffer[ MAXIMUM_FILENAME_LENGTH ]; + ANSI_STRING AnsiDisplayString; + UNICODE_STRING DisplayString; + + UNICODE_STRING CmdLine; + WCHAR CmdLineBuffer[ 2 * MAXIMUM_FILENAME_LENGTH ]; + UNICODE_STRING NtDllName; + PVOID NtDllHandle; + PMESSAGE_RESOURCE_ENTRY MessageEntry; + PSZ CheckingString = NULL; + + // + // Query the system environment variable "osloadoptions" to determine + // if SOS is specified. + // + + if (SmpQueryRegistrySosOption() != FALSE) { + SmpEnableDots = FALSE; + } + + RtlInitUnicodeString(&NtDllName, L"ntdll"); + Status = LdrGetDllHandle( + NULL, + NULL, + &NtDllName, + &NtDllHandle + ); + + if ( NT_SUCCESS(Status) ) { + Status = RtlFindMessage( + NtDllHandle, + 11, +#if defined(DBCS) // SmpInvokeAutoChk() + // + // We have to use ENGLISH resource anytime instead of default resource. Because + // We can only display ASCII character onto Blue Screen via HalDisplayString() + // + MAKELANGID(LANG_ENGLISH,SUBLANG_ENGLISH_US), +#else + 0, +#endif // defined(DBCS) + STATUS_CHECKING_FILE_SYSTEM, + &MessageEntry + ); + if ( NT_SUCCESS(Status) ) { + CheckingString = MessageEntry->Text; + } + } + + if (!CheckingString) { + CheckingString = "Checking File System on %wZ\n"; + } + + if (Flags & SMP_IMAGE_NOT_FOUND) { + sprintf( DisplayBuffer, + "%wZ program not found - skipping AUTOCHECK\n", + ImageFileName + ); + + RtlInitAnsiString( &AnsiDisplayString, DisplayBuffer ); + Status = RtlAnsiStringToUnicodeString( &DisplayString, + &AnsiDisplayString, + TRUE + ); + if (NT_SUCCESS( Status )) { + NtDisplayString( &DisplayString ); + RtlFreeUnicodeString( &DisplayString ); + } + + return( STATUS_SUCCESS ); + } + + RtlInitUnicodeString( &ArgPrefix, L"/p " ); + if (RtlPrefixUnicodeString( &ArgPrefix, Arguments, TRUE )) { + Arguments->Length -= 3 * sizeof( WCHAR ); + RtlMoveMemory( Arguments->Buffer, + Arguments->Buffer + 3, + Arguments->Length + ); + ForceAutoChk = TRUE; + } + else { + ForceAutoChk = FALSE; + } + + CmdLine.Buffer = CmdLineBuffer; + CmdLine.MaximumLength = sizeof( CmdLineBuffer ); + RtlInitUnicodeString( &LinkTarget, L"*" ); + if (!RtlEqualUnicodeString( Arguments, &LinkTarget, TRUE )) { + CmdLine.Length = 0; + RtlAppendUnicodeStringToString( &CmdLine, ImageFileName ); + RtlAppendUnicodeToString( &CmdLine, L" " ); + if (ForceAutoChk) { + RtlAppendUnicodeToString( &CmdLine, L"/p " ); + } + RtlAppendUnicodeStringToString( &CmdLine, Arguments ); + SmpExecuteImage( ImageFileName, + CurrentDirectory, + &CmdLine, + Flags & ~SMP_AUTOCHK_FLAG, + NULL + ); + } + else { + LinkTarget.Buffer = LinkTargetBuffer; + + DirInfo = (POBJECT_DIRECTORY_INFORMATION)&DirInfoBuffer; + RestartScan = TRUE; + RtlInitUnicodeString( &LinkTypeName, L"SymbolicLink" ); + RtlInitUnicodeString( &LinkTargetPrefix, L"\\Device\\Harddisk" ); + while (TRUE) { + + Status = NtQueryDirectoryObject( SmpDosDevicesObjectDirectory, + (PVOID)DirInfo, + sizeof( DirInfoBuffer ), + TRUE, + RestartScan, + &Context, + &Length + ); + if (!NT_SUCCESS( Status )) { + Status = STATUS_SUCCESS; + break; + } + + if (RtlEqualUnicodeString( &DirInfo->TypeName, &LinkTypeName, TRUE ) && + DirInfo->Name.Buffer[(DirInfo->Name.Length>>1)-1] == L':') { + InitializeObjectAttributes( &ObjectAttributes, + &DirInfo->Name, + OBJ_CASE_INSENSITIVE, + SmpDosDevicesObjectDirectory, + NULL + ); + Status = NtOpenSymbolicLinkObject( &Handle, + SYMBOLIC_LINK_ALL_ACCESS, + &ObjectAttributes + ); + if (NT_SUCCESS( Status )) { + LinkTarget.Length = 0; + LinkTarget.MaximumLength = sizeof( LinkTargetBuffer ); + Status = NtQuerySymbolicLinkObject( Handle, + &LinkTarget, + NULL + ); + NtClose( Handle ); + if (NT_SUCCESS( Status ) && + RtlPrefixUnicodeString( &LinkTargetPrefix, &LinkTarget, TRUE ) + ) { + sprintf( DisplayBuffer, + CheckingString, + &DirInfo->Name + ); + + if (SmpEnableDots != FALSE) { + RtlInitAnsiString( &AnsiDisplayString, "." ); + + } else { + RtlInitAnsiString( &AnsiDisplayString, DisplayBuffer ); + } + + Status = RtlAnsiStringToUnicodeString( &DisplayString, + &AnsiDisplayString, + TRUE + ); + + if (NT_SUCCESS( Status )) { + NtDisplayString( &DisplayString ); + RtlFreeUnicodeString( &DisplayString ); + } + CmdLine.Length = 0; + RtlAppendUnicodeStringToString( &CmdLine, ImageFileName ); + RtlAppendUnicodeToString( &CmdLine, L" " ); + if (ForceAutoChk) { + RtlAppendUnicodeToString( &CmdLine, L"/p " ); + } + RtlAppendUnicodeToString( &CmdLine, L" /d" ); + RtlAppendUnicodeToString( &CmdLine, DirInfo->Name.Buffer ); + RtlAppendUnicodeToString( &CmdLine, L" " ); + RtlAppendUnicodeStringToString( &CmdLine, &LinkTarget ); + SmpExecuteImage( ImageFileName, + CurrentDirectory, + &CmdLine, + Flags & ~SMP_AUTOCHK_FLAG, + NULL + ); + } + } + } + + RestartScan = FALSE; + if (!NT_SUCCESS( Status )) { + break; + } + } + } + + return( Status ); +} + +NTSTATUS +SmpLoadSubSystem( + IN PUNICODE_STRING ImageFileName, + IN PUNICODE_STRING CurrentDirectory, + IN PUNICODE_STRING CommandLine, + IN ULONG Flags + ) + +/*++ + +Routine Description: + + This function loads and starts the specified system service + emulation subsystem. The system freezes until the loaded subsystem + completes the subsystem connection protocol by connecting to SM, + and then accepting a connection from SM. + +Arguments: + + CommandLine - Supplies the command line to execute the subsystem. + +Return Value: + + TBD + +--*/ + +{ + NTSTATUS Status; + RTL_USER_PROCESS_INFORMATION ProcessInformation; + PSMPKNOWNSUBSYS KnownSubSys; + PSMPKNOWNSUBSYS TargetSubSys; + + + if (Flags & SMP_IMAGE_NOT_FOUND) { + KdPrint(( "SMSS: Unable to find subsystem - %wZ\n", ImageFileName )); + return( STATUS_OBJECT_NAME_NOT_FOUND ); + } + + Flags |= SMP_DONT_START; + Status = SmpExecuteImage( ImageFileName, + CurrentDirectory, + CommandLine, + Flags, + &ProcessInformation + ); + if (!NT_SUCCESS( Status )) { + return( Status ); + } + + KnownSubSys = RtlAllocateHeap( SmpHeap, MAKE_TAG( INIT_TAG ), sizeof( SMPKNOWNSUBSYS ) ); + KnownSubSys->Process = ProcessInformation.Process; + KnownSubSys->InitialClientId = ProcessInformation.ClientId; + KnownSubSys->ImageType = (ULONG)0xFFFFFFFF; + KnownSubSys->SmApiCommunicationPort = (HANDLE) NULL; + KnownSubSys->SbApiCommunicationPort = (HANDLE) NULL; + + Status = NtCreateEvent( &KnownSubSys->Active, + EVENT_ALL_ACCESS, + NULL, + NotificationEvent, + FALSE + ); + // + // now that we have the process all set, make sure that the + // subsystem is either an NT native app, or an app type of + // a previously loaded subsystem + // + + if (ProcessInformation.ImageInformation.SubSystemType != + IMAGE_SUBSYSTEM_NATIVE ) { + SBAPIMSG SbApiMsg; + PSBCREATESESSION args; + ULONG SessionId; + + args = &SbApiMsg.u.CreateSession; + + args->ProcessInformation = ProcessInformation; + args->DebugSession = 0; + args->DebugUiClientId.UniqueProcess = NULL; + args->DebugUiClientId.UniqueThread = NULL; + + TargetSubSys = SmpLocateKnownSubSysByType( + ProcessInformation.ImageInformation.SubSystemType + ); + if ( !TargetSubSys ) { + return STATUS_NO_SUCH_PACKAGE; + } + // + // Transfer the handles to the subsystem responsible for this + // process + // + + Status = NtDuplicateObject( NtCurrentProcess(), + ProcessInformation.Process, + TargetSubSys->Process, + &args->ProcessInformation.Process, + PROCESS_ALL_ACCESS, + 0, + 0 + ); + if (!NT_SUCCESS( Status )) { + return( Status ); + } + + Status = NtDuplicateObject( NtCurrentProcess(), + ProcessInformation.Thread, + TargetSubSys->Process, + &args->ProcessInformation.Thread, + THREAD_ALL_ACCESS, + 0, + 0 + ); + if (!NT_SUCCESS( Status )) { + return( Status ); + } + + SessionId = SmpAllocateSessionId( TargetSubSys, + NULL + ); + args->SessionId = SessionId; + + SbApiMsg.ApiNumber = SbCreateSessionApi; + SbApiMsg.h.u1.s1.DataLength = sizeof(*args) + 8; + SbApiMsg.h.u1.s1.TotalLength = sizeof(SbApiMsg); + SbApiMsg.h.u2.ZeroInit = 0L; + + Status = NtRequestWaitReplyPort( + TargetSubSys->SbApiCommunicationPort, + (PPORT_MESSAGE) &SbApiMsg, + (PPORT_MESSAGE) &SbApiMsg + ); + + if (NT_SUCCESS( Status )) { + Status = SbApiMsg.ReturnedStatus; + } + + if (!NT_SUCCESS( Status )) { + SmpDeleteSession( SessionId, FALSE, Status ); + return( Status ); + } + } + else { + SmpWindowsSubSysProcess = ProcessInformation.Process; + } + + ASSERTMSG( "NtCreateEvent", NT_SUCCESS( Status ) ); + + RtlEnterCriticalSection( &SmpKnownSubSysLock ); + + InsertHeadList( &SmpKnownSubSysHead, &KnownSubSys->Links ); + + RtlLeaveCriticalSection( &SmpKnownSubSysLock ); + + NtResumeThread( ProcessInformation.Thread, NULL ); + + NtWaitForSingleObject( KnownSubSys->Active, FALSE, NULL ); + + return STATUS_SUCCESS; +} + + +NTSTATUS +SmpExecuteInitialCommand( + IN PUNICODE_STRING InitialCommand, + OUT PHANDLE InitialCommandProcess + ) +{ + NTSTATUS Status; + RTL_USER_PROCESS_INFORMATION ProcessInformation; + ULONG Flags; + UNICODE_STRING ImageFileName; + UNICODE_STRING CurrentDirectory; + UNICODE_STRING Arguments; + HANDLE SmApiPort; + + Status = SmConnectToSm( NULL, + NULL, + 0, + &SmApiPort + ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: Unable to connect to SM - Status == %lx\n", Status )); + return( Status ); + } + + Flags = 0; + Status = SmpParseCommandLine( InitialCommand, + &Flags, + &ImageFileName, + &CurrentDirectory, + &Arguments + ); + if (Flags & SMP_IMAGE_NOT_FOUND) { + KdPrint(( "SMSS: Initial command image (%wZ) not found\n", &ImageFileName )); + return( STATUS_OBJECT_NAME_NOT_FOUND ); + } + + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: SmpParseCommand( %wZ ) failed - Status == %lx\n", InitialCommand, Status )); + return( Status ); + } + + Status = SmpExecuteImage( &ImageFileName, + &CurrentDirectory, + InitialCommand, + SMP_DONT_START, + &ProcessInformation + ); + if (!NT_SUCCESS( Status )) { + return( Status ); + } + + Status = NtDuplicateObject( NtCurrentProcess(), + ProcessInformation.Process, + NtCurrentProcess(), + InitialCommandProcess, + PROCESS_ALL_ACCESS, + 0, + 0 + ); + + if (!NT_SUCCESS(Status) ) { + KdPrint(( "SMSS: DupObject Failed. Status == %lx\n", + Status + )); + NtTerminateProcess( ProcessInformation.Process, Status ); + NtResumeThread( ProcessInformation.Thread, NULL ); + NtClose( ProcessInformation.Thread ); + NtClose( ProcessInformation.Process ); + return( Status ); + } + + Status = SmExecPgm( SmApiPort, + &ProcessInformation, + FALSE + ); + + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: SmExecPgm Failed. Status == %lx\n", + Status + )); + return( Status ); + } + + return( Status ); +} + + +void +SmpDisplayString( char *s ) +{ + ANSI_STRING AnsiString; + UNICODE_STRING UnicodeString; + + RtlInitAnsiString( &AnsiString, s ); + + RtlAnsiStringToUnicodeString( &UnicodeString, &AnsiString, TRUE ); + + NtDisplayString( &UnicodeString ); + + RtlFreeUnicodeString( &UnicodeString ); +} + +NTSTATUS +SmpLoadDeferedSubsystem( + IN PSMAPIMSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT CallingClient, + IN HANDLE CallPort + ) +{ + + NTSTATUS Status; + PLIST_ENTRY Head, Next; + PSMP_REGISTRY_VALUE p; + UNICODE_STRING DeferedName; + PSMLOADDEFERED args; + + args = &SmApiMsg->u.LoadDefered; + + DeferedName.Length = (USHORT)args->SubsystemNameLength; + DeferedName.MaximumLength = (USHORT)args->SubsystemNameLength; + DeferedName.Buffer = args->SubsystemName; + + Head = &SmpSubSystemsToDefer; + Next = Head->Flink; + while (Next != Head ) { + p = CONTAINING_RECORD( Next, + SMP_REGISTRY_VALUE, + Entry + ); + if ( RtlEqualUnicodeString(&DeferedName,&p->Name,TRUE)) { + + // + // This is it. Load the subsystem... + // + + RemoveEntryList(Next); + + Status = SmpExecuteCommand( &p->Value, SMP_SUBSYSTEM_FLAG ); + + RtlFreeHeap( RtlProcessHeap(), 0, p ); + + return Status; + + } + Next = Next->Flink; + } + return STATUS_OBJECT_NAME_NOT_FOUND; +} + + +NTSTATUS +SmpConfigureProtectionMode( + IN PWSTR ValueName, + IN ULONG ValueType, + IN PVOID ValueData, + IN ULONG ValueLength, + IN PVOID Context, + IN PVOID EntryContext + ) +/*++ + +Routine Description: + + This function is a dispatch routine for the QueryRegistry call + (see SmpRegistryConfigurationTable[] earlier in this file). + + The purpose of this routine is to read the Base Object Protection + Mode out of the registry. This information is kept in + + Key Name: \\Hkey_Local_Machine\System\CurrentControlSet\SessionManager + Value: ProtectionMode [REG_DWORD] + + The value is a flag word, with the following flags defined: + + SMP_NO_PROTECTION - No base object protection + SMP_STANDARD_PROTECTION - Apply standard base + object protection + + This information will be placed in the global variable + SmpProtectionMode. + + No value, or an invalid value length or type results in no base + object protection being applied. + +Arguments: + + None. + +Return Value: + + +--*/ +{ + + +#ifdef SMP_SHOW_REGISTRY_DATA + SmpDumpQuery( "BaseObjectsProtection", ValueName, ValueType, ValueData, ValueLength ); +#else + UNREFERENCED_PARAMETER( ValueName ); + UNREFERENCED_PARAMETER( ValueType ); +#endif + + + + if (ValueLength != sizeof(ULONG)) { + + // + // Key value not valid, set to run without base object protection. + // This is how we initialized, so no need to set up new + // security descriptors. + // + + SmpProtectionMode = 0; + + } else { + + + SmpProtectionMode = (*((PULONG)(ValueData))); + + // + // Change the security descriptors + // + + (VOID)SmpCreateSecurityDescriptors( FALSE ); + } + + return( STATUS_SUCCESS ); +} + + +NTSTATUS +SmpCreateSecurityDescriptors( + IN BOOLEAN InitialCall + ) + +/*++ + +Routine Description: + + This function allocates and initializes security descriptors + used in SM. + + The security descriptors include: + + SmpPrimarySecurityDescriptor - (global variable) This is + used to assign protection to objects created by + SM that need to be accessed by others, but not modified. + This descriptor grants the following access: + + Grant: World: Execute | Read (Inherit) + Grant: Admin: All Access (Inherit) + Grant: Owner: All Access (Inherit Only) + + SmpLiberalSecurityDescriptor = (globalVariable) This is used + to assign protection objects created by SM that need + to be modified by others (such as writing to a shared + memory section). + This descriptor grants the following access: + + Grant: World: Execute | Read | Write (Inherit) + Grant: Admin: All Access (Inherit) + Grant: Owner: All Access (Inherit Only) + + SmpKnownDllsSecurityDescriptor = (globalVariable) This is used + to assign protection to the \KnownDlls object directory. + This descriptor grants the following access: + + Grant: World: Execute (No Inherit) + Grant: Admin: All Access (Inherit) + Grant: World: Execute | Read | Write (Inherit Only) + + + Note that System is an administrator, so granting Admin an + access also grants System that access. + +Arguments: + + InitialCall - Indicates whether this routine is being called for + the first time, or is being called to change the security + descriptors as a result of a protection mode change. + + TRUE - being called for first time. + FALSE - being called a subsequent time. + + (global variables: SmpBaseObjectsUnprotected) + +Return Value: + + STATUS_SUCCESS - The security descriptor(s) have been allocated + and initialized. + + STATUS_NO_MEMORY - couldn't allocate memory for a security + descriptor. + +--*/ + +{ + NTSTATUS + Status; + + PSID + WorldSid, + AdminSid, + OwnerSid; + + SID_IDENTIFIER_AUTHORITY + WorldAuthority = SECURITY_WORLD_SID_AUTHORITY, + NtAuthority = SECURITY_NT_AUTHORITY, + CreatorAuthority = SECURITY_CREATOR_SID_AUTHORITY; + + ACCESS_MASK + AdminAccess = (GENERIC_ALL), + WorldAccess = (GENERIC_EXECUTE | GENERIC_READ), + OwnerAccess = (GENERIC_ALL); + + UCHAR + InheritOnlyFlags = (OBJECT_INHERIT_ACE | + CONTAINER_INHERIT_ACE | + INHERIT_ONLY_ACE); + + ULONG + AceIndex, + AclLength; + + PACL + Acl; + + PACE_HEADER + Ace; + + BOOLEAN + ProtectionRequired = FALSE, + WasEnabled; + + + if (InitialCall) { + + // + // Now init the security descriptors for no protection. + // If told to, we will change these to have protection. + // + + // Primary + + SmpPrimarySecurityDescriptor = &SmpPrimarySDBody; + Status = RtlCreateSecurityDescriptor ( + SmpPrimarySecurityDescriptor, + SECURITY_DESCRIPTOR_REVISION + ); + ASSERT( NT_SUCCESS(Status) ); + Status = RtlSetDaclSecurityDescriptor ( + SmpPrimarySecurityDescriptor, + TRUE, //DaclPresent, + NULL, //Dacl (no protection) + FALSE //DaclDefaulted OPTIONAL + ); + ASSERT( NT_SUCCESS(Status) ); + + + // Liberal + + SmpLiberalSecurityDescriptor = &SmpLiberalSDBody; + Status = RtlCreateSecurityDescriptor ( + SmpLiberalSecurityDescriptor, + SECURITY_DESCRIPTOR_REVISION + ); + ASSERT( NT_SUCCESS(Status) ); + Status = RtlSetDaclSecurityDescriptor ( + SmpLiberalSecurityDescriptor, + TRUE, //DaclPresent, + NULL, //Dacl (no protection) + FALSE //DaclDefaulted OPTIONAL + ); + ASSERT( NT_SUCCESS(Status) ); + + // KnownDlls + + SmpKnownDllsSecurityDescriptor = &SmpKnownDllsSDBody; + Status = RtlCreateSecurityDescriptor ( + SmpKnownDllsSecurityDescriptor, + SECURITY_DESCRIPTOR_REVISION + ); + ASSERT( NT_SUCCESS(Status) ); + Status = RtlSetDaclSecurityDescriptor ( + SmpKnownDllsSecurityDescriptor, + TRUE, //DaclPresent, + NULL, //Dacl (no protection) + FALSE //DaclDefaulted OPTIONAL + ); + ASSERT( NT_SUCCESS(Status) ); + + + // ApiPort + + SmpApiPortSecurityDescriptor = &SmpApiPortSDBody; + Status = RtlCreateSecurityDescriptor ( + SmpApiPortSecurityDescriptor, + SECURITY_DESCRIPTOR_REVISION + ); + ASSERT( NT_SUCCESS(Status) ); + Status = RtlSetDaclSecurityDescriptor ( + SmpApiPortSecurityDescriptor, + TRUE, //DaclPresent, + NULL, //Dacl (no protection) + FALSE //DaclDefaulted OPTIONAL + ); + ASSERT( NT_SUCCESS(Status) ); + } + + + + if ((SmpProtectionMode & SMP_PROTECTION_REQUIRED) != 0) { + ProtectionRequired = TRUE; + } + + if (!InitialCall && !ProtectionRequired) { + return(STATUS_SUCCESS); + } + + + + if (InitialCall || ProtectionRequired) { + + // + // We need to set up the ApiPort protection, and maybe + // others. + // + + Status = RtlAllocateAndInitializeSid( + &WorldAuthority, + 1, + SECURITY_WORLD_RID, + 0, 0, 0, 0, 0, 0, 0, + &WorldSid + ); + + if (NT_SUCCESS( Status )) { + + Status = RtlAllocateAndInitializeSid( + &NtAuthority, + 2, + SECURITY_BUILTIN_DOMAIN_RID, + DOMAIN_ALIAS_RID_ADMINS, + 0, 0, 0, 0, 0, 0, + &AdminSid + ); + + if (NT_SUCCESS( Status )) { + + Status = RtlAllocateAndInitializeSid( + &CreatorAuthority, + 1, + SECURITY_CREATOR_OWNER_RID, + 0, 0, 0, 0, 0, 0, 0, + &OwnerSid + ); + + if (NT_SUCCESS( Status )) { + + // + // Build the ApiPort security descriptor only + // if this is the initial call + // + + if (InitialCall) { + + WorldAccess = GENERIC_EXECUTE | GENERIC_READ | GENERIC_READ; + AdminAccess = GENERIC_ALL; + + AclLength = sizeof( ACL ) + + 2 * sizeof( ACCESS_ALLOWED_ACE ) + + (RtlLengthSid( WorldSid )) + + (RtlLengthSid( AdminSid )); + + Acl = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), AclLength ); + + if (Acl == NULL) { + Status = STATUS_NO_MEMORY; + } + + if (NT_SUCCESS(Status)) { + + // + // Create the ACL, then add each ACE + // + + Status = RtlCreateAcl (Acl, AclLength, ACL_REVISION2 ); + ASSERT( NT_SUCCESS(Status) ); + + // + // Only Non-inheritable ACEs in this ACL + // World + // Admin + // + + Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid ); + ASSERT( NT_SUCCESS(Status) ); + + Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid ); + ASSERT( NT_SUCCESS(Status) ); + + + Status = RtlSetDaclSecurityDescriptor ( + SmpApiPortSecurityDescriptor, + TRUE, //DaclPresent, + Acl, //Dacl + FALSE //DaclDefaulted OPTIONAL + ); + ASSERT( NT_SUCCESS(Status) ); + } + } + + // + // The remaining security descriptors are only + // built if we are running with the correct in + // protection mode set. Notice that we only + // put protection on if standard protection is + // also specified. Otherwise, there is no protection + // on the objects, and nothing should fail. + // + + if (SmpProtectionMode & SMP_STANDARD_PROTECTION) { + + // + // Build the primary Security descriptor + // + + WorldAccess = GENERIC_EXECUTE | GENERIC_READ; + AdminAccess = GENERIC_ALL; + OwnerAccess = GENERIC_ALL; + + AclLength = sizeof( ACL ) + + 5 * sizeof( ACCESS_ALLOWED_ACE ) + + (2*RtlLengthSid( WorldSid )) + + (2*RtlLengthSid( AdminSid )) + + RtlLengthSid( OwnerSid ); + + Acl = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), AclLength ); + + if (Acl == NULL) { + Status = STATUS_NO_MEMORY; + } + + if (NT_SUCCESS(Status)) { + + // + // Create the ACL, then add each ACE + // + + Status = RtlCreateAcl (Acl, AclLength, ACL_REVISION2 ); + ASSERT( NT_SUCCESS(Status) ); + + // + // Non-inheritable ACEs first + // World + // Admin + // + + AceIndex = 0; + Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid ); + ASSERT( NT_SUCCESS(Status) ); + + AceIndex++; + Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid ); + ASSERT( NT_SUCCESS(Status) ); + + // + // Inheritable ACEs at end of ACE + // World + // Admin + // Owner + + AceIndex++; + Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid ); + ASSERT( NT_SUCCESS(Status) ); + Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace ); + ASSERT( NT_SUCCESS(Status) ); + Ace->AceFlags = InheritOnlyFlags; + + AceIndex++; + Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid ); + ASSERT( NT_SUCCESS(Status) ); + Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace ); + ASSERT( NT_SUCCESS(Status) ); + Ace->AceFlags = InheritOnlyFlags; + + AceIndex++; + Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, OwnerAccess, OwnerSid ); + ASSERT( NT_SUCCESS(Status) ); + Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace ); + ASSERT( NT_SUCCESS(Status) ); + Ace->AceFlags = InheritOnlyFlags; + + + + Status = RtlSetDaclSecurityDescriptor ( + SmpPrimarySecurityDescriptor, + TRUE, //DaclPresent, + Acl, //Dacl + FALSE //DaclDefaulted OPTIONAL + ); + ASSERT( NT_SUCCESS(Status) ); + } + + + + + // + // Build the liberal security descriptor + // + + + AdminAccess = GENERIC_ALL; + WorldAccess = GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE; + + AclLength = sizeof( ACL ) + + 5 * sizeof( ACCESS_ALLOWED_ACE ) + + (2*RtlLengthSid( WorldSid )) + + (2*RtlLengthSid( AdminSid )) + + RtlLengthSid( OwnerSid ); + + Acl = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), AclLength ); + + if (Acl == NULL) { + Status = STATUS_NO_MEMORY; + } + + if (NT_SUCCESS(Status)) { + + // + // Create the ACL + // + + Status = RtlCreateAcl (Acl, AclLength, ACL_REVISION2 ); + ASSERT( NT_SUCCESS(Status) ); + + // + // Add the non-inheritable ACEs first + // World + // Admin + // + + AceIndex = 0; + Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid ); + ASSERT( NT_SUCCESS(Status) ); + + AceIndex++; + Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid ); + ASSERT( NT_SUCCESS(Status) ); + + // + // Put the inherit only ACEs at at the end + // World + // Admin + // Owner + // + + AceIndex++; + Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid ); + ASSERT( NT_SUCCESS(Status) ); + Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace ); + ASSERT( NT_SUCCESS(Status) ); + Ace->AceFlags = InheritOnlyFlags; + + AceIndex++; + Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid ); + ASSERT( NT_SUCCESS(Status) ); + Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace ); + ASSERT( NT_SUCCESS(Status) ); + Ace->AceFlags = InheritOnlyFlags; + + AceIndex++; + Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, OwnerAccess, OwnerSid ); + ASSERT( NT_SUCCESS(Status) ); + Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace ); + ASSERT( NT_SUCCESS(Status) ); + Ace->AceFlags = InheritOnlyFlags; + + + // + // Put the Acl in the security descriptor + // + + Status = RtlSetDaclSecurityDescriptor ( + SmpLiberalSecurityDescriptor, + TRUE, //DaclPresent, + Acl, //Dacl + FALSE //DaclDefaulted OPTIONAL + ); + ASSERT( NT_SUCCESS(Status) ); + } + + + // + // Build the KnownDlls security descriptor + // + + + AdminAccess = GENERIC_ALL; + + AclLength = sizeof( ACL ) + + 4 * sizeof( ACCESS_ALLOWED_ACE ) + + (2*RtlLengthSid( WorldSid )) + + (2*RtlLengthSid( AdminSid )); + + Acl = RtlAllocateHeap( RtlProcessHeap(), MAKE_TAG( INIT_TAG ), AclLength ); + + if (Acl == NULL) { + Status = STATUS_NO_MEMORY; + } + + if (NT_SUCCESS(Status)) { + + // + // Create the ACL + // + + Status = RtlCreateAcl (Acl, AclLength, ACL_REVISION2 ); + ASSERT( NT_SUCCESS(Status) ); + + // + // Add the non-inheritable ACEs first + // World + // Admin + // + + AceIndex = 0; + WorldAccess = GENERIC_EXECUTE; + Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid ); + ASSERT( NT_SUCCESS(Status) ); + + AceIndex++; + Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid ); + ASSERT( NT_SUCCESS(Status) ); + + // + // Put the inherit only ACEs at at the end + // World + // Admin + // + + AceIndex++; + WorldAccess = GENERIC_EXECUTE | GENERIC_READ | GENERIC_WRITE; + Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, WorldAccess, WorldSid ); + ASSERT( NT_SUCCESS(Status) ); + Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace ); + ASSERT( NT_SUCCESS(Status) ); + Ace->AceFlags = InheritOnlyFlags; + + AceIndex++; + Status = RtlAddAccessAllowedAce ( Acl, ACL_REVISION2, AdminAccess, AdminSid ); + ASSERT( NT_SUCCESS(Status) ); + Status = RtlGetAce( Acl, AceIndex, (PVOID)&Ace ); + ASSERT( NT_SUCCESS(Status) ); + Ace->AceFlags = InheritOnlyFlags; + + + // + // Put the Acl in the security descriptor + // + + Status = RtlSetDaclSecurityDescriptor ( + SmpKnownDllsSecurityDescriptor, + TRUE, //DaclPresent, + Acl, //Dacl + FALSE //DaclDefaulted OPTIONAL + ); + ASSERT( NT_SUCCESS(Status) ); + } + + + } + + + // + // No more security descriptors to build + // + + RtlFreeHeap( RtlProcessHeap(), 0, OwnerSid ); + } + RtlFreeHeap( RtlProcessHeap(), 0, AdminSid ); + } + RtlFreeHeap( RtlProcessHeap(), 0, WorldSid ); + } + } + + return( Status ); + +} + + +VOID +SmpTranslateSystemPartitionInformation( VOID ) + +/*++ + +Routine Description: + + This routine translates the NT device path for the system partition (stored + during IoInitSystem) into a DOS path, and stores the resulting REG_SZ 'BootDir' + value under HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup + +Arguments: + + None. + +Return Value: + + None. + +--*/ + +{ + NTSTATUS Status; + UNICODE_STRING UnicodeString; + OBJECT_ATTRIBUTES ObjectAttributes; + HANDLE Key; + UCHAR ValueBuffer[ VALUE_BUFFER_SIZE ]; + ULONG ValueLength; + UNICODE_STRING SystemPartitionString; + POBJECT_DIRECTORY_INFORMATION DirInfo; + UCHAR DirInfoBuffer[ sizeof(OBJECT_DIRECTORY_INFORMATION) + (256 + sizeof("SymbolicLink")) * sizeof(WCHAR) ]; + UNICODE_STRING LinkTypeName; + BOOLEAN RestartScan; + ULONG Context; + HANDLE SymbolicLinkHandle; + WCHAR UnicodeBuffer[ MAXIMUM_FILENAME_LENGTH ]; + UNICODE_STRING LinkTarget; + + // + // Retrieve 'SystemPartition' value stored under HKLM\SYSTEM\Setup + // + + RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\System\\Setup"); + InitializeObjectAttributes(&ObjectAttributes, + &UnicodeString, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + Status = NtOpenKey(&Key, KEY_READ, &ObjectAttributes); + if (!NT_SUCCESS(Status)) { + KdPrint(("SMSS: can't open system setup key for reading: 0x%x\n", Status)); + return; + } + + RtlInitUnicodeString(&UnicodeString, L"SystemPartition"); + Status = NtQueryValueKey(Key, + &UnicodeString, + KeyValuePartialInformation, + ValueBuffer, + sizeof(ValueBuffer), + &ValueLength + ); + + NtClose(Key); + + if (!NT_SUCCESS(Status)) { + KdPrint(("SMSS: can't query SystemPartition value: 0x%x\n", Status)); + return; + } + + RtlInitUnicodeString(&SystemPartitionString, + (PWSTR)(((PKEY_VALUE_PARTIAL_INFORMATION)ValueBuffer)->Data) + ); + + // + // Next, examine objects in the DosDevices directory, looking for one that's a symbolic link + // to the system partition. + // + + LinkTarget.Buffer = UnicodeBuffer; + + DirInfo = (POBJECT_DIRECTORY_INFORMATION)DirInfoBuffer; + RestartScan = TRUE; + RtlInitUnicodeString(&LinkTypeName, L"SymbolicLink"); + + while (TRUE) { + + Status = NtQueryDirectoryObject(SmpDosDevicesObjectDirectory, + DirInfo, + sizeof(DirInfoBuffer), + TRUE, + RestartScan, + &Context, + NULL + ); + + if (!NT_SUCCESS(Status)) { + break; + } + + if (RtlEqualUnicodeString(&DirInfo->TypeName, &LinkTypeName, TRUE) && + (DirInfo->Name.Length == 2 * sizeof(WCHAR)) && + (DirInfo->Name.Buffer[1] == L':')) { + + // + // We have a drive letter--check the NT device name it's linked to. + // + + InitializeObjectAttributes(&ObjectAttributes, + &DirInfo->Name, + OBJ_CASE_INSENSITIVE, + SmpDosDevicesObjectDirectory, + NULL + ); + + Status = NtOpenSymbolicLinkObject(&SymbolicLinkHandle, + SYMBOLIC_LINK_ALL_ACCESS, + &ObjectAttributes + ); + + if (NT_SUCCESS(Status)) { + + LinkTarget.Length = 0; + LinkTarget.MaximumLength = sizeof(UnicodeBuffer); + + Status = NtQuerySymbolicLinkObject(SymbolicLinkHandle, + &LinkTarget, + NULL + ); + NtClose(SymbolicLinkHandle); + + if (NT_SUCCESS(Status) && + RtlEqualUnicodeString(&SystemPartitionString, &LinkTarget, TRUE)) { + + // + // We've found the drive letter corresponding to the system partition. + // + + break; + } + } + } + + RestartScan = FALSE; + } + + if (!NT_SUCCESS(Status)) { + KdPrint(("SMSS: can't find drive letter for system partition\n")); + return; + } + + // + // Now write out the DOS path for the system partition to + // HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Setup + // + + RtlInitUnicodeString(&UnicodeString, L"\\Registry\\Machine\\Software\\Microsoft\\Windows\\CurrentVersion\\Setup"); + InitializeObjectAttributes(&ObjectAttributes, + &UnicodeString, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + Status = NtOpenKey(&Key, KEY_ALL_ACCESS, &ObjectAttributes); + if (!NT_SUCCESS(Status)) { + KdPrint(("SMSS: can't open software setup key for writing: 0x%x\n", Status)); + return; + } + + wcsncpy(UnicodeBuffer, DirInfo->Name.Buffer, 2); + UnicodeBuffer[2] = L'\\'; + UnicodeBuffer[3] = L'\0'; + + RtlInitUnicodeString(&UnicodeString, L"BootDir"); + + Status = NtSetValueKey(Key, + &UnicodeString, + 0, + REG_SZ, + UnicodeBuffer, + 4 * sizeof(WCHAR) + ); + + if (!NT_SUCCESS(Status)) { + KdPrint(("SMSS: couldn't write BootDir value: 0x%x\n", Status)); + } + + NtClose(Key); +} + diff --git a/private/sm/server/smloop.c b/private/sm/server/smloop.c new file mode 100644 index 000000000..d54d470bd --- /dev/null +++ b/private/sm/server/smloop.c @@ -0,0 +1,451 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + smloop.c + +Abstract: + + Session Manager Listen and API loops + +Author: + + Mark Lucovsky (markl) 04-Oct-1989 + +Revision History: + +--*/ + +#include "smsrvp.h" + + +NTSTATUS +SmpHandleConnectionRequest( + IN HANDLE ConnectionPort, + IN PSBAPIMSG Message + ); + + +PSMAPI SmpApiDispatch[SmMaxApiNumber] = { + SmpCreateForeignSession, + SmpSessionComplete, + SmpTerminateForeignSession, + SmpExecPgm, + SmpLoadDeferedSubsystem + }; + + +#if DBG +PSZ SmpApiName[ SmMaxApiNumber+1 ] = { + "SmCreateForeignSession", + "SmSessionComplete", + "SmTerminateForeignSession", + "SmExecPgm", + "SmLoadDeferedSubsystem", + "Unknown Sm Api Number" +}; +#endif // DBG + +EXCEPTION_DISPOSITION +DbgpUnhandledExceptionFilter( + struct _EXCEPTION_POINTERS *ExceptionInfo + ); + + +NTSTATUS +SmpApiLoop ( + IN PVOID ThreadParameter + ) + +/*++ + +Routine Description: + + This is the main Session Manager API Loop. It + services session manager API requests. + +Arguments: + + ThreadParameter - Supplies a handle to the API port used + to receive session manager API requests. + +Return Value: + + None. + +--*/ + +{ + PSMAPIMSG SmApiReplyMsg; + SMMESSAGE_SIZE MsgBuf; + + PSMAPIMSG SmApiMsg; + NTSTATUS Status; + HANDLE ConnectionPort; + PSMP_CLIENT_CONTEXT ClientContext; + PSMPKNOWNSUBSYS KnownSubSys; + + + ConnectionPort = (HANDLE) ThreadParameter; + + SmApiMsg = (PSMAPIMSG)&MsgBuf; + SmApiReplyMsg = NULL; + try { + for(;;) { + + Status = NtReplyWaitReceivePort( + ConnectionPort, + (PVOID *) &ClientContext, + (PPORT_MESSAGE) SmApiReplyMsg, + (PPORT_MESSAGE) SmApiMsg + ); + if ( !NT_SUCCESS(Status) ) { + SmApiReplyMsg = NULL; + continue; + } else if ( SmApiMsg->h.u2.s2.Type == LPC_CONNECTION_REQUEST ) { + SmpHandleConnectionRequest( ConnectionPort, + (PSBAPIMSG) SmApiMsg + ); + SmApiReplyMsg = NULL; + } else if ( SmApiMsg->h.u2.s2.Type == LPC_DEBUG_EVENT ) { + ASSERT(SmpDbgSsLoaded); + DbgSsHandleKmApiMsg((PDBGKM_APIMSG)SmApiMsg,NULL); + SmApiReplyMsg = NULL; + } else if ( SmApiMsg->h.u2.s2.Type == LPC_PORT_CLOSED ) { + SmApiReplyMsg = NULL; + } else { + KnownSubSys = ClientContext->KnownSubSys; + + SmApiMsg->ReturnedStatus = STATUS_PENDING; + +#if DBG && 0 + if (SmApiMsg->ApiNumber >= SmMaxApiNumber ) { + SmApiMsg->ApiNumber = SmMaxApiNumber; + } + KdPrint(( "SMSS: %s Api Request received from %lx.%lx\n", + SmpApiName[ SmApiMsg->ApiNumber ], + SmApiMsg->h.ClientId.UniqueProcess, + SmApiMsg->h.ClientId.UniqueThread + )); +#endif // DBG + + if (SmApiMsg->ApiNumber >= SmMaxApiNumber ) { + + Status = STATUS_NOT_IMPLEMENTED; + + } else { + + switch (SmApiMsg->ApiNumber) { + case SmExecPgmApi : + Status = (SmpApiDispatch[SmApiMsg->ApiNumber])( + SmApiMsg, + ClientContext, + ConnectionPort); + break; + + case SmLoadDeferedSubsystemApi : + Status = (SmpApiDispatch[SmApiMsg->ApiNumber])( + SmApiMsg, + ClientContext, + ConnectionPort); + break; + + + case SmCreateForeignSessionApi : + case SmSessionCompleteApi : + case SmTerminateForeignSessionApi : + if (!KnownSubSys) { + Status = STATUS_INVALID_PARAMETER; + } else { + + Status = + (SmpApiDispatch[SmApiMsg->ApiNumber])( + SmApiMsg, + ClientContext, + ConnectionPort); + } + break; + + } + + } + + SmApiMsg->ReturnedStatus = Status; + SmApiReplyMsg = SmApiMsg; + } + } + } except (DbgpUnhandledExceptionFilter( GetExceptionInformation() )) { + ; + } + + // + // Make the compiler happy + // + + return STATUS_UNSUCCESSFUL; +} + + +NTSTATUS +SmpHandleConnectionRequest( + IN HANDLE ConnectionPort, + IN PSBAPIMSG Message + ) + +/*++ + +Routine Description: + + This routine handles connection requests from either known subsystems, + or other clients. Other clients are admin processes. + + The protocol for connection from a known subsystem is: + + capture the name of the sub systems Sb API port + + Accept the connection + + Connect to the subsystems Sb API port + + Store the communication port handle in the known subsystem database + + signal the event associated with the known subsystem + + The protocol for others is to simply validate and accept the connection + request. + +Arguments: + +Return Value: + + None. + +--*/ + +{ + NTSTATUS st; + HANDLE CommunicationPort; + REMOTE_PORT_VIEW ClientView; + PSBCONNECTINFO ConnectInfo; + ULONG ConnectInfoLength; + PSMPKNOWNSUBSYS KnownSubSys; + BOOLEAN Accept; + UNICODE_STRING SubSystemPort; + SECURITY_QUALITY_OF_SERVICE DynamicQos; + PSMP_CLIENT_CONTEXT ClientContext; + + // + // Set up the security quality of service parameters to use over the + // sb API port. Use the most efficient (least overhead) - which is dynamic + // rather than static tracking. + // + + DynamicQos.ImpersonationLevel = SecurityIdentification; + DynamicQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; + DynamicQos.EffectiveOnly = TRUE; + + + ConnectInfo = &Message->ConnectionRequest; + KnownSubSys = SmpLocateKnownSubSysByCid(&Message->h.ClientId); + + if ( KnownSubSys ) { + + if ( SmpLocateKnownSubSysByType(ConnectInfo->SubsystemImageType) == + KnownSubSys ) { + Accept = FALSE; + KdPrint(("SMSS: Connection from SubSystem rejected\n")); + KdPrint(("SMSS: Image type already being served\n")); + } else { + Accept = TRUE; + KnownSubSys->ImageType = ConnectInfo->SubsystemImageType; + } + } else { + + // + // Authenticate the SOB + // + + Accept = TRUE; + + } + + if (Accept) { + ClientContext = RtlAllocateHeap(SmpHeap, MAKE_TAG( SM_TAG ), sizeof(SMP_CLIENT_CONTEXT)); + ClientContext->KnownSubSys = KnownSubSys; + } + + ClientView.Length = sizeof(ClientView); + st = NtAcceptConnectPort( + &CommunicationPort, + ClientContext, + (PPORT_MESSAGE)Message, + Accept, + NULL, + &ClientView + ); + ASSERT( NT_SUCCESS(st) ); + + if ( Accept ) { + + if ( KnownSubSys ) { + KnownSubSys->SmApiCommunicationPort = CommunicationPort; + } + + st = NtCompleteConnectPort(CommunicationPort); + ASSERT( NT_SUCCESS(st) ); + + // + // Connect Back to subsystem + // + + if ( KnownSubSys ) { + RtlCreateUnicodeString( &SubSystemPort, + ConnectInfo->EmulationSubSystemPortName + ); + ConnectInfoLength = sizeof( *ConnectInfo ); + + st = NtConnectPort( + &KnownSubSys->SbApiCommunicationPort, + &SubSystemPort, + &DynamicQos, + NULL, + NULL, + NULL, + NULL, + NULL + ); + if ( !NT_SUCCESS(st) ) { + KdPrint(("SMSS: Connect back to Sb %wZ failed %lx\n",&SubSystemPort,st)); + } + + RtlFreeUnicodeString( &SubSystemPort ); + NtSetEvent(KnownSubSys->Active,NULL); + } + } + + return st; +} + + +PSMPKNOWNSUBSYS +SmpLocateKnownSubSysByCid( + IN PCLIENT_ID ClientId + ) + +/*++ + +Routine Description: + + This function scans the known sub system table looking for + a matching client id (just UniqueProcess portion). If found, + than the connection request is from a known subsystem and + accept is always granted. Otherwise, it must be an administrative + process. + +Arguments: + + ClientId - Supplies the ClientId whose UniqueProcess field is to be used + in the known subsystem scan. + +Return Value: + + NULL - The ClientId does not match a known subsystem. + + NON-NULL - Returns the address of the known subsystem. + +--*/ + +{ + + PSMPKNOWNSUBSYS KnownSubSys = NULL; + PLIST_ENTRY Next; + + // + // Aquire known subsystem lock + // + + RtlEnterCriticalSection(&SmpKnownSubSysLock); + + Next = SmpKnownSubSysHead.Flink; + + while ( Next != &SmpKnownSubSysHead ) { + + KnownSubSys = CONTAINING_RECORD(Next,SMPKNOWNSUBSYS,Links); + Next = Next->Flink; + + if ( KnownSubSys->InitialClientId.UniqueProcess == ClientId->UniqueProcess ) { + break; + } else { + KnownSubSys = NULL; + } + } + + // + // Unlock known subsystems + // + + RtlLeaveCriticalSection(&SmpKnownSubSysLock); + + return KnownSubSys; +} + + +PSMPKNOWNSUBSYS +SmpLocateKnownSubSysByType( + IN ULONG ImageType + ) + +/*++ + +Routine Description: + + This function scans the known sub system table looking for + a matching image type. + +Arguments: + + ImageType - Supplies the image type whose sub system is to be located. + +Return Value: + + NULL - The image type does not match a known subsystem. + + NON-NULL - Returns the address of the known subsystem. + +--*/ + +{ + + PSMPKNOWNSUBSYS KnownSubSys = NULL; + PLIST_ENTRY Next; + + // + // Aquire known subsystem lock + // + + RtlEnterCriticalSection(&SmpKnownSubSysLock); + + Next = SmpKnownSubSysHead.Flink; + + while ( Next != &SmpKnownSubSysHead ) { + + KnownSubSys = CONTAINING_RECORD(Next,SMPKNOWNSUBSYS,Links); + Next = Next->Flink; + + if ( KnownSubSys->ImageType == ImageType ) { + break; + } else { + KnownSubSys = NULL; + } + } + + // + // Unlock known subsystems + // + + RtlLeaveCriticalSection(&SmpKnownSubSysLock); + + return KnownSubSys; +} diff --git a/private/sm/server/smsbapi.c b/private/sm/server/smsbapi.c new file mode 100644 index 000000000..f037f739b --- /dev/null +++ b/private/sm/server/smsbapi.c @@ -0,0 +1,215 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + smsbapi.c + +Abstract: + + Session Manager stubs which call subsystem + +Author: + + Mark Lucovsky (markl) 04-Oct-1989 + +Revision History: + +--*/ + +#include "smsrvp.h" + +#if DBG +PCHAR SmpSubSystemNames[] = { + "Unknown", + "Native", + "Windows", + "Posix", + "OS/2" +}; +#endif + +NTSTATUS +SmpSbCreateSession ( + IN PSMPSESSION SourceSession OPTIONAL, + IN PSMPKNOWNSUBSYS CreatorSubsystem OPTIONAL, + IN PRTL_USER_PROCESS_INFORMATION ProcessInformation, + IN ULONG DebugSession OPTIONAL, + IN PCLIENT_ID DebugUiClientId OPTIONAL + ) +{ + NTSTATUS st; + PSMPKNOWNSUBSYS KnownSubSys; + SBAPIMSG SbApiMsg; + PSBCREATESESSION args; + ULONG SessionId; + PSMPPROCESS Process; + + args = &SbApiMsg.u.CreateSession; + + args->ProcessInformation = *ProcessInformation; + args->DebugSession = DebugSession; + + if (ARGUMENT_PRESENT(DebugUiClientId)) { + args->DebugUiClientId = *DebugUiClientId; + } else { + args->DebugUiClientId.UniqueProcess = NULL; + args->DebugUiClientId.UniqueThread = NULL; + } + + KnownSubSys = SmpLocateKnownSubSysByType( + ProcessInformation->ImageInformation.SubSystemType + ); + + if ( !KnownSubSys ) { + + + // + // BUGBUG markl this needs alot more thought + // + + if (ProcessInformation->ImageInformation.SubSystemType != + IMAGE_SUBSYSTEM_NATIVE ) { +#if DBG + DbgPrint( "SMSS: %s SubSystem has not been started.\n", + SmpSubSystemNames[ ProcessInformation->ImageInformation.SubSystemType ] + ); +#endif + return STATUS_UNSUCCESSFUL; + } + + + if ( args->DebugUiClientId.UniqueProcess != NULL || + args->DebugUiClientId.UniqueThread != NULL ) { + + if ( SmpDbgSsLoaded ) { + + // + // This is a native process + // Create a process and insert it + // in the hash list + // + + Process = RtlAllocateHeap(SmpHeap, MAKE_TAG( SM_TAG ), sizeof(SMPPROCESS)); + + Process->DebugUiClientId = args->DebugUiClientId; + Process->ConnectionKey = ProcessInformation->ClientId; + + // + // BUGBUG FIX THIS + // + + InsertHeadList(&NativeProcessList,&Process->Links); + + DbgPrint("Native Debug App %lx.%lx\n", + Process->ConnectionKey.UniqueProcess, + Process->ConnectionKey.UniqueThread + ); + + // + // Process is being debugged, so set up debug port + // + + st = NtSetInformationProcess( + ProcessInformation->Process, + ProcessDebugPort, + &SmpDebugPort, + sizeof(HANDLE) + ); + ASSERT(NT_SUCCESS(st)); + } + } + + + // + // Start closing handles + // + + NtClose(ProcessInformation->Process); + + NtResumeThread(ProcessInformation->Thread,NULL); + + NtClose(ProcessInformation->Thread); + + return STATUS_SUCCESS; + } + + + // + // Transfer the handles to the subsystem responsible for this + // process + // + + st = NtDuplicateObject( + NtCurrentProcess(), + ProcessInformation->Process, + KnownSubSys->Process, + &args->ProcessInformation.Process, + PROCESS_ALL_ACCESS, + 0, + 0 + ); + + if ( !NT_SUCCESS(st) ) { + + DbgPrint("SmpSbCreateSession: NtDuplicateObject (Process) Failed %lx\n",st); + return st; + } + + st = NtDuplicateObject( + NtCurrentProcess(), + ProcessInformation->Thread, + KnownSubSys->Process, + &args->ProcessInformation.Thread, + THREAD_ALL_ACCESS, + 0, + 0 + ); + + if ( !NT_SUCCESS(st) ) { + + // + // Need to do more here + // + + NtClose(ProcessInformation->Process); + + DbgPrint("SmpSbCreateSession: NtDuplicateObject (Thread) Failed %lx\n",st); + return st; + } + + NtClose(ProcessInformation->Process); + NtClose(ProcessInformation->Thread); + + SessionId = SmpAllocateSessionId( + KnownSubSys, + CreatorSubsystem + ); + + args->SessionId = SessionId; + + SbApiMsg.ApiNumber = SbCreateSessionApi; + SbApiMsg.h.u1.s1.DataLength = sizeof(*args) + 8; + SbApiMsg.h.u1.s1.TotalLength = sizeof(SbApiMsg); + SbApiMsg.h.u2.ZeroInit = 0L; + + st = NtRequestWaitReplyPort( + KnownSubSys->SbApiCommunicationPort, + (PPORT_MESSAGE) &SbApiMsg, + (PPORT_MESSAGE) &SbApiMsg + ); + + if ( NT_SUCCESS(st) ) { + st = SbApiMsg.ReturnedStatus; + } else { + DbgPrint("SmpSbCreateSession: NtRequestWaitReply Failed %lx\n",st); + } + + if ( !NT_SUCCESS(st) ) { + SmpDeleteSession(SessionId,FALSE,st); + } + + return st; + +} diff --git a/private/sm/server/smsesnid.c b/private/sm/server/smsesnid.c new file mode 100644 index 000000000..24fe463b3 --- /dev/null +++ b/private/sm/server/smsesnid.c @@ -0,0 +1,231 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + smsesnid.c + +Abstract: + + Session Manager Session ID Management + +Author: + + Mark Lucovsky (markl) 04-Oct-1989 + +Revision History: + +--*/ + +#include "smsrvp.h" +#include <string.h> + + +ULONG +SmpAllocateSessionId( + IN PSMPKNOWNSUBSYS OwningSubsystem, + IN PSMPKNOWNSUBSYS CreatorSubsystem OPTIONAL + ) + +/*++ + +Routine Description: + + This function allocates a session id. + +Arguments: + + OwningSubsystem - Supplies the address of the subsystem that should + become the owner of this session. + + + CreatorSubsystem - An optional parameter that if supplied supplies + the address of the subsystem requesting the creation of this + session. This subsystem is notified when the session completes. + +Return Value: + + This function returns the session id for this session. + +--*/ + +{ + + ULONG SessionId; + PLIST_ENTRY SessionIdListInsertPoint; + PSMPSESSION Session; + + RtlEnterCriticalSection(&SmpSessionListLock); + + // + // SessionId's are allocated by incrementing a 32 bit counter. + // If the counter wraps, then session id's are allocated by + // scaning the sorted list of current session id's for a hole. + // + + SessionId = SmpNextSessionId++; + SessionIdListInsertPoint = SmpSessionListHead.Blink; + + if ( !SmpNextSessionIdScanMode ) { + + if ( SmpNextSessionId == 0 ) { + + // + // We have used up 32 bits worth of session id's so + // enable scan mode session id allocation. + // + + SmpNextSessionIdScanMode = TRUE; + } + + } else { + + // + // Compute a session id by scanning the sorted session id list + // until a whole is found. When an id is found, then save it, + // and re-calculate the inster point. + // + + DbgPrint("SMSS: SessionId's Wraped\n"); + DbgBreakPoint(); + + } + + Session = RtlAllocateHeap(SmpHeap, MAKE_TAG( SM_TAG ), sizeof(SMPSESSION)); + + Session->SessionId = SessionId; + Session->OwningSubsystem = OwningSubsystem; + Session->CreatorSubsystem = CreatorSubsystem; + + InsertTailList(SessionIdListInsertPoint,&Session->SortedSessionIdListLinks); + + RtlLeaveCriticalSection(&SmpSessionListLock); + + return SessionId; +} + + +PSMPSESSION +SmpSessionIdToSession( + IN ULONG SessionId + ) + +/*++ + +Routine Description: + + This function locates the session structure for the specified + session id. + + It is assumed that the caller holds the session list lock. + +Arguments: + + SessionId - Supplies the session id whose session structure + located + +Return Value: + + NULL - No session matches the specified session + + NON-NULL - Returns a pointer to the session structure associated with + the specified session id. + +--*/ + +{ + + PLIST_ENTRY Next; + PSMPSESSION Session; + + Next = SmpSessionListHead.Flink; + while ( Next != &SmpSessionListHead ) { + Session = CONTAINING_RECORD(Next, SMPSESSION, SortedSessionIdListLinks ); + + if ( Session->SessionId == SessionId ) { + return Session; + } + Next = Session->SortedSessionIdListLinks.Flink; + } + + return NULL; +} + + +VOID +SmpDeleteSession( + IN ULONG SessionId, + IN BOOLEAN SendSessionComplete, + IN NTSTATUS SessionStatus + ) + +/*++ + +Routine Description: + + This function locates and deletes a session id. If the + SendSessionComplete flag is true, then it also sends a session + complete message to the creator subsystem. + +Arguments: + + SessionId - Supplies the session id to delete. + + SendSessionComplete - Specifies whether a session complete message + is to be sent to the creator subsystem (if one exists). + + SessionStatus - Supplies the session completion status + + +Return Value: + + +--*/ + +{ + + PSMPSESSION Session; + PSMPKNOWNSUBSYS CreatorSubsystem; + + RtlEnterCriticalSection(&SmpSessionListLock); + + Session = SmpSessionIdToSession(SessionId); + + if ( Session ) { + + RemoveEntryList(&Session->SortedSessionIdListLinks); + + + RtlLeaveCriticalSection(&SmpSessionListLock); + + CreatorSubsystem = Session->CreatorSubsystem; + + RtlFreeHeap(SmpHeap,0,Session); + + // + // If there is a creator subsystem, and if + // told to send a session complete message, then do it. + // + + if ( CreatorSubsystem && SendSessionComplete ) { + + // + // Foreign Session Complete + // + } + + } else { + + RtlLeaveCriticalSection(&SmpSessionListLock); + } + + return; + + + // + // Make the compiler happy + // + + SessionStatus; +} diff --git a/private/sm/server/smsmapi.c b/private/sm/server/smsmapi.c new file mode 100644 index 000000000..fd68412e8 --- /dev/null +++ b/private/sm/server/smsmapi.c @@ -0,0 +1,238 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + smsmapi.c + +Abstract: + + Implementation of Session Manager Sm APIs + +Author: + + Mark Lucovsky (markl) 04-Oct-1989 + +Revision History: + +--*/ + +#include "smsrvp.h" + + +NTSTATUS +SmpCreateForeignSession( + IN PSMAPIMSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT CallingClient, + IN HANDLE CallPort + ) +{ + SmApiMsg; // Unreferrence formal parameter. + CallingClient; // Unreferrence formal parameter. + CallPort; // Unreferrence formal parameter. + + return STATUS_NOT_IMPLEMENTED; +} + + + + + +NTSTATUS +SmpSessionComplete( + IN PSMAPIMSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT CallingClient, + IN HANDLE CallPort + ) + +/*++ + +Routine Description: + + This API is called by a subsystem to report that a session is + complete. A check is made to ensure that the calling subsystem + owns the completed session. If so, then the session is deleted. + +Arguments: + + SmApiMsg - Supplies the API message + + CallingClient - Supplies the address of the context block for the calling + client. + + CallPort - The port over which the call was received. + +Return Value: + + TBD + +--*/ + +{ + PSMPSESSION Session; + PSMSESSIONCOMPLETE args; + NTSTATUS st; + + CallPort; // Unreferrence formal parameter. + + args = &SmApiMsg->u.SessionComplete; + + RtlEnterCriticalSection(&SmpSessionListLock); + + Session = SmpSessionIdToSession(args->SessionId); + + RtlLeaveCriticalSection(&SmpSessionListLock); + + // + // If a session is found, then ensure that calling subsystem is its + // owner + // + + if ( Session ) { + + if ( Session->OwningSubsystem == CallingClient->KnownSubSys ) { + + SmpDeleteSession(args->SessionId,TRUE,args->CompletionStatus); + st = STATUS_SUCCESS; + + } else { + + st = STATUS_INVALID_PARAMETER; + + } + + } else { + + st = STATUS_INVALID_PARAMETER; + + } + + return st; +} + + +NTSTATUS +SmpTerminateForeignSession( + IN PSMAPIMSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT CallingClient, + IN HANDLE CallPort + ) +{ + SmApiMsg; // Unreferrence formal parameter. + CallingClient; // Unreferrence formal parameter. + CallPort; // Unreferrence formal parameter. + + return STATUS_NOT_IMPLEMENTED; +} + + + + +NTSTATUS +SmpExecPgm( + IN PSMAPIMSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT CallingClient, + IN HANDLE CallPort + ) +{ + NTSTATUS st; + HANDLE SourceProcess; + OBJECT_ATTRIBUTES ObjectAttributes; + PSMEXECPGM args; + RTL_USER_PROCESS_INFORMATION ProcessInformation; + PCLIENT_ID Cid; + PCLIENT_ID DebugUiClientId; + + CallingClient; // Unreferrence formal parameter. + CallPort; // Unreferrence formal parameter. + + // + // open a handle to the calling process so the + // handles that it is passing can be duped + // + + InitializeObjectAttributes( &ObjectAttributes, NULL, 0, NULL, NULL ); + st = NtOpenProcess( + &SourceProcess, + PROCESS_DUP_HANDLE, + &ObjectAttributes, + &SmApiMsg->h.ClientId + ); + + if (!NT_SUCCESS(st) ) { + DbgPrint("SmExecPgm: NtOpenProcess Failed %lx\n",st); + return st; + } + + args = &SmApiMsg->u.ExecPgm; + + ProcessInformation = args->ProcessInformation; + + // + // Get all handles in our table + // + + st = NtDuplicateObject( + SourceProcess, + args->ProcessInformation.Process, + NtCurrentProcess(), + &ProcessInformation.Process, + PROCESS_ALL_ACCESS, + 0, + 0 + ); + + if ( !NT_SUCCESS(st) ) { + NtClose(SourceProcess); + DbgPrint("SmExecPgm: NtDuplicateObject (Process) Failed %lx\n",st); + return st; + } + + st = NtDuplicateObject( + SourceProcess, + args->ProcessInformation.Thread, + NtCurrentProcess(), + &ProcessInformation.Thread, + THREAD_ALL_ACCESS, + 0, + 0 + ); + + if ( !NT_SUCCESS(st) ) { + NtClose(ProcessInformation.Process); + NtClose(SourceProcess); + DbgPrint("SmExecPgm: NtDuplicateObject (Thread) Failed %lx\n",st); + return st; + } + + // + // Done getting the handles, so close our handle to the calling + // process and call the appropriate subsystem to start the process. + // + + NtClose(SourceProcess); + + + + // + // All handles passed are closed + // by SmpSbCreateSession + // + + if ( args->DebugFlag ) { + DebugUiClientId = &SmApiMsg->h.ClientId; + } else { + DebugUiClientId = NULL; + } + + st = SmpSbCreateSession( + NULL, + NULL, + &ProcessInformation, + 0L, + DebugUiClientId + ); + + return st; +} diff --git a/private/sm/server/smsrvp.h b/private/sm/server/smsrvp.h new file mode 100644 index 000000000..fe8407569 --- /dev/null +++ b/private/sm/server/smsrvp.h @@ -0,0 +1,551 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + smsrvp.h + +Abstract: + + Session Manager Private Types and Prototypes + +Author: + + Mark Lucovsky (markl) 04-Oct-1989 + +Revision History: + +--*/ + +#ifndef _SMSRVP_ +#define _SMSRVP_ + +#include <nt.h> +#include <ntrtl.h> +#include <nturtl.h> +#include <ntsm.h> +#include <ntdbg.h> +#include <stdlib.h> +#include "sm.h" + + +// +// Types +// + + +typedef struct _SMPKNOWNSUBSYS { + LIST_ENTRY Links; + HANDLE Active; + HANDLE Process; + ULONG ImageType; + HANDLE SmApiCommunicationPort; + HANDLE SbApiCommunicationPort; + CLIENT_ID InitialClientId; +} SMPKNOWNSUBSYS, *PSMPKNOWNSUBSYS; + +typedef struct _SMP_CLIENT_CONTEXT { + PSMPKNOWNSUBSYS KnownSubSys; + HANDLE ClientProcessHandle; +} SMP_CLIENT_CONTEXT, *PSMP_CLIENT_CONTEXT; + + +typedef struct _SMPSESSION { + LIST_ENTRY SortedSessionIdListLinks; + ULONG SessionId; + PSMPKNOWNSUBSYS OwningSubsystem; + PSMPKNOWNSUBSYS CreatorSubsystem; +} SMPSESSION, *PSMPSESSION; + +typedef struct _SMPPROCESS { + LIST_ENTRY Links; + CLIENT_ID DebugUiClientId; + CLIENT_ID ConnectionKey; +} SMPPROCESS, *PSMPPROCESS; + +// +// Global Data +// + +RTL_CRITICAL_SECTION SmpKnownSubSysLock; +LIST_ENTRY SmpKnownSubSysHead; + +LIST_ENTRY NativeProcessList; + +RTL_CRITICAL_SECTION SmpSessionListLock; +LIST_ENTRY SmpSessionListHead; +ULONG SmpNextSessionId; +BOOLEAN SmpNextSessionIdScanMode; + + +ULONG SmpDebug; +HANDLE SmpDebugPort; +BOOLEAN SmpDbgSsLoaded; +PDBGSS_INITIALIZE_ROUTINE SmpDbgInitRoutine; +PDBGSS_HANDLE_MSG_ROUTINE SmpDbgHandleMsgRoutine; + +UNICODE_STRING SmpSubsystemName; +HANDLE SmpKnownDllObjectDirectory; +HANDLE SmpKnownDllFileDirectory; +UNICODE_STRING SmpKnownDllPath; +HANDLE SmpDosDevicesObjectDirectory; + +PVOID SmpHeap; + +LUID SmpTcbPrivilege; + +PVOID SmpDefaultEnvironment; + +PTOKEN_OWNER SmpSmOwnerSid; +ULONG SmpSmOwnerSidLength; + +UNICODE_STRING SmpDefaultLibPath; +WCHAR *SmpDefaultLibPathBuffer; + +UNICODE_STRING SmpSystemRoot; +WCHAR *SmpSystemRootBuffer; + + +// +// Session Manager Apis +// + +typedef +NTSTATUS +(* PSMAPI)( + IN PSMAPIMSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT CallingClient, + IN HANDLE CallPort + ); + + +NTSTATUS +SmpCreateForeignSession( + IN PSMAPIMSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT CallingClient, + IN HANDLE CallPort + ); + +NTSTATUS +SmpSessionComplete( + IN PSMAPIMSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT CallingClient, + IN HANDLE CallPort + ); + +NTSTATUS +SmpTerminateForeignSession( + IN PSMAPIMSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT CallingClient, + IN HANDLE CallPort + ); + +NTSTATUS +SmpExecPgm( // Temporary Hack + IN PSMAPIMSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT CallingClient, + IN HANDLE CallPort + ); + +NTSTATUS +SmpLoadDeferedSubsystem( + IN PSMAPIMSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT CallingClient, + IN HANDLE CallPort + ); + + +// +// Private Prototypes +// + +NTSTATUS +SmpExecuteInitialCommand( + IN PUNICODE_STRING InitialCommand, + OUT PHANDLE InitialCommandProcess + ); + +NTSTATUS +SmpApiLoop ( + IN PVOID ThreadParameter + ); + +NTSTATUS +SmpInit( + OUT PUNICODE_STRING InitialCommand, + OUT PHANDLE WindowsSubSystem + ); + +NTSTATUS +SmpExecuteImage( + IN PUNICODE_STRING ImageFileName, + IN PUNICODE_STRING CurrentDirectory, + IN PUNICODE_STRING CommandLine, + IN ULONG Flags, + IN OUT PRTL_USER_PROCESS_INFORMATION ProcessInformation OPTIONAL + ); + +NTSTATUS +SmpLoadDbgSs( + IN PUNICODE_STRING DbgSsName + ); + +PSMPKNOWNSUBSYS +SmpLocateKnownSubSysByCid( + IN PCLIENT_ID ClientId + ); + +PSMPKNOWNSUBSYS +SmpLocateKnownSubSysByType( + IN ULONG ImageType + ); + +ULONG +SmpAllocateSessionId( + IN PSMPKNOWNSUBSYS OwningSubsystem, + IN PSMPKNOWNSUBSYS CreatorSubsystem OPTIONAL + ); + +PSMPSESSION +SmpSessionIdToSession( + IN ULONG SessionId + ); + +VOID +SmpDeleteSession( + IN ULONG SessionId, + IN BOOLEAN SendSessionComplete, + IN NTSTATUS SessionStatus + ); + +// +// Stubs for Sb APIs +// + +NTSTATUS +SmpSbCreateSession ( + IN PSMPSESSION SourceSession OPTIONAL, + IN PSMPKNOWNSUBSYS CreatorSubsystem OPTIONAL, + IN PRTL_USER_PROCESS_INFORMATION ProcessInformation, + IN ULONG DebugSession OPTIONAL, + IN PCLIENT_ID DebugUiClientId OPTIONAL + ); + +ULONG SmBaseTag; + +#define MAKE_TAG( t ) (RTL_HEAP_MAKE_TAG( SmBaseTag, t )) + +#define INIT_TAG 0 +#define DBG_TAG 1 +#define SM_TAG 2 + +// +// Constants +// + +// +// When a subsystem connects, its process is opened. This allows us +// to duplicate objects into and out of the subsystem. +// + +#define DBGP_OPEN_SUBSYSTEM_ACCESS (PROCESS_DUP_HANDLE | READ_CONTROL) + +// +// When a user interface connects, its process is opened. This allows us +// to duplicate objects into and out of the user interface. +// + +#define DBGP_OPEN_UI_ACCESS (PROCESS_DUP_HANDLE | READ_CONTROL) + +// +// When an application thread is made known to Dbg, it is opened with the +// following access. Once the thread is picked up (through +// DbgUiWaitStateChange), the handle is duplicated into its user +// interface and the local handle is closed. +// + +#define DBGP_OPEN_APP_THREAD_ACCESS \ + (THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME | \ + THREAD_QUERY_INFORMATION | READ_CONTROL | THREAD_TERMINATE) + +#define DBGP_DUP_APP_THREAD_ACCESS \ + (THREAD_GET_CONTEXT | THREAD_SET_CONTEXT | THREAD_SUSPEND_RESUME | \ + THREAD_QUERY_INFORMATION | READ_CONTROL | THREAD_TERMINATE) +// +// When an application process is made known to Dbg, it is opened with the +// following access. Once the process is picked up (through +// DbgUiWaitStateChange), the handle is duplicated into its user +// interface and the local handle is closed. +// + +#define DBGP_OPEN_APP_PROCESS_ACCESS \ + (PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | \ + PROCESS_DUP_HANDLE | PROCESS_TERMINATE | PROCESS_SET_PORT | \ + READ_CONTROL | PROCESS_QUERY_INFORMATION | PROCESS_CREATE_THREAD ) + +#define DBGP_DUP_APP_PROCESS_ACCESS \ + (PROCESS_VM_READ | PROCESS_VM_WRITE | PROCESS_VM_OPERATION | \ + PROCESS_DUP_HANDLE | PROCESS_QUERY_INFORMATION | READ_CONTROL | PROCESS_CREATE_THREAD | PROCESS_TERMINATE ) + +// +// When a DLL is loaded or a process created, the file associated with the +// DLL/EXE is dupped into the UI. The following access is granted to the UI +// + +#define DBGP_DUP_APP_FILE_ACCESS ( SYNCHRONIZE | GENERIC_READ ) + +// +// Types +// + +// +// Each DebugUi client of Dbg is assigned a user interface structure. +// From this structure, all of the the threads controlled by the user +// interface can be found. +// + +// +// Subsystems are represented by the following data structure. All +// DbgSs APIs implicitly pass the address of this structure. +// + +typedef struct _DBGP_SUBSYSTEM { + CLIENT_ID SubsystemClientId; + HANDLE CommunicationPort; + HANDLE SubsystemProcessHandle; +} DBGP_SUBSYSTEM, *PDBGP_SUBSYSTEM; + +// +// Dbg maintains a handle to the DebugUi client represented by this data +// structure. The handle only has PROCESS_DUP_HANDLE access since this +// handle is only used to transfer handles into the DebugUi +// + +typedef struct _DBGP_USER_INTERFACE { + CLIENT_ID DebugUiClientId; + HANDLE CommunicationPort; + HANDLE DebugUiProcess; + HANDLE StateChangeSemaphore; + RTL_CRITICAL_SECTION UserInterfaceLock; + LIST_ENTRY AppProcessListHead; + LIST_ENTRY HashTableLinks; +} DBGP_USER_INTERFACE, *PDBGP_USER_INTERFACE; + +// +// Each application process is represented by the following structure +// + +typedef struct _DBGP_APP_PROCESS { + LIST_ENTRY AppThreadListHead; + LIST_ENTRY AppLinks; + LIST_ENTRY HashTableLinks; + CLIENT_ID AppClientId; + PDBGP_USER_INTERFACE UserInterface; + HANDLE DbgSrvHandleToProcess; + HANDLE HandleToProcess; +} DBGP_APP_PROCESS, *PDBGP_APP_PROCESS; + +// +// Each application thread is represented by the following structure +// + +typedef struct _DBGP_APP_THREAD { + LIST_ENTRY AppLinks; + LIST_ENTRY HashTableLinks; + CLIENT_ID AppClientId; + DBG_STATE CurrentState; + DBG_STATE ContinueState; + PDBGP_APP_PROCESS AppProcess; + PDBGP_USER_INTERFACE UserInterface; + HANDLE HandleToThread; + PDBGP_SUBSYSTEM Subsystem; + DBGSS_APIMSG LastSsApiMsg; +} DBGP_APP_THREAD, *PDBGP_APP_THREAD; + +typedef +NTSTATUS +(*PDBGSS_API) ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ); + +typedef +NTSTATUS +(*PDBGUI_API) ( + IN PDBGP_USER_INTERFACE UserInterface, + IN OUT PDBGUI_APIMSG ApiMsg + ); + +// +// Global Data +// + + +// +// Applications being debugged are assigned an DBGP_APP_THREAD structure. +// The application thread is linked into the DbgpAppClientIdHashTable +// while processing a "CreateThread" message. Insertion and deletion +// into this table is done under control of the DbgAppLock. +// + +#define DBGP_CLIENT_ID_HASHSIZE 32 + +#define DBGP_PROCESS_CLIENT_ID_TO_INDEX(pclient_id) (\ + ((ULONG)((pclient_id)->UniqueProcess))&(DBGP_CLIENT_ID_HASHSIZE-1)) + +#define DBGP_THREAD_CLIENT_ID_TO_INDEX(pclient_id) (\ + ((ULONG)((pclient_id)->UniqueThread))&(DBGP_CLIENT_ID_HASHSIZE-1)) + +RTL_CRITICAL_SECTION DbgpHashTableLock; +LIST_ENTRY DbgpAppThreadHashTable[DBGP_CLIENT_ID_HASHSIZE]; +LIST_ENTRY DbgpAppProcessHashTable[DBGP_CLIENT_ID_HASHSIZE]; +LIST_ENTRY DbgpUiHashTable[DBGP_CLIENT_ID_HASHSIZE]; + +HANDLE DbgpSsApiPort; +HANDLE DbgpUiApiPort; + +// +// Macros +// + +#define DBGP_CLIENT_IDS_EQUAL(pid1,pid2) (\ + (pid1)->UniqueProcess == (pid2)->UniqueProcess && \ + (pid1)->UniqueThread == (pid2)->UniqueThread ) + +#define DBGP_REPORTING_STATE_CHANGE(pAppThread) (\ + pAppThread->CurrentState != DbgIdle && pAppThread->CurrentState != DbgReplyPending ) + +// +// Implementation of DbgSs APIs +// + +NTSTATUS +DbgpSsException ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ); + +NTSTATUS +DbgpSsCreateThread ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ); + +NTSTATUS +DbgpSsCreateProcess ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ); + +NTSTATUS +DbgpSsExitThread ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ); + +NTSTATUS +DbgpSsExitProcess ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ); + +NTSTATUS +DbgpSsLoadDll ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ); + +NTSTATUS +DbgpSsUnloadDll ( + IN PDBGP_SUBSYSTEM Subsystem, + IN OUT PDBGSS_APIMSG ApiMsg + ); + +// +// Implementation of DbgUi APIs +// + +NTSTATUS +DbgpUiWaitStateChange ( + IN PDBGP_USER_INTERFACE UserInterface, + IN OUT PDBGUI_APIMSG ApiMsg + ); + +NTSTATUS +DbgpUiContinue ( + IN PDBGP_USER_INTERFACE UserInterface, + IN OUT PDBGUI_APIMSG ApiMsg + ); + +// +// Private Prototypes +// + +NTSTATUS +DbgpSsApiLoop ( + IN PVOID ThreadParameter + ); + +NTSTATUS +DbgpUiApiLoop ( + IN PVOID ThreadParameter + ); + +NTSTATUS +DbgpInit( + VOID + ); + +// +// User Interface Support Routines +// + +PDBGP_USER_INTERFACE +DbgpIsUiInHashTable( + IN PCLIENT_ID DebugUiClientId + ); + +// +// App Support Routines +// + +PDBGP_APP_THREAD +DbgpIsAppInHashTable( + IN PCLIENT_ID AppClientId + ); + +PDBGP_APP_THREAD +DbgpLocateStateChangeApp( + IN PDBGP_USER_INTERFACE UserInterface, + OUT PDBG_STATE PreviousState + ); + +PDBGP_APP_PROCESS +DbgpIsAppProcessInHashTable( + IN PCLIENT_ID AppClientId + ); + +VOID +DbgpUiHasTerminated( + IN PCLIENT_ID DebugUiClientId + ); + +#if DBG + +// +// Dump Routines +// + +VOID +DbgpDumpUserInterface ( + IN PDBGP_USER_INTERFACE UserInterface + ); + +VOID +DbgpDumpSubsystem ( + IN PDBGP_SUBSYSTEM Subsystem + ); +#endif // DBG + +#endif // _SMSRVP_ diff --git a/private/sm/server/smss.c b/private/sm/server/smss.c new file mode 100644 index 000000000..1e198d3af --- /dev/null +++ b/private/sm/server/smss.c @@ -0,0 +1,206 @@ +/*++ + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + smss.c + +Abstract: + + +Author: + + Mark Lucovsky (markl) 04-Oct-1989 + +Revision History: + +--*/ + +#include "smsrvp.h" + +EXCEPTION_DISPOSITION +SmpUnhandledExceptionFilter( + struct _EXCEPTION_POINTERS *ExceptionInfo + ); + +void +_CRTAPI1 main( + int argc, + char *argv[], + char *envp[], + ULONG DebugParameter OPTIONAL + ) +{ + NTSTATUS Status; + KPRIORITY SetBasePriority; + UNICODE_STRING InitialCommand, DebugInitialCommand, UnicodeParameter; + HANDLE ProcessHandles[ 2 ]; + ULONG Parameters[ 4 ]; + ULONG Response; + PROCESS_BASIC_INFORMATION ProcessInfo; + BOOLEAN WasEnabled; + + SetBasePriority = FOREGROUND_BASE_PRIORITY+2; + Status = NtSetInformationProcess( NtCurrentProcess(), + ProcessBasePriority, + (PVOID) &SetBasePriority, + sizeof( SetBasePriority ) + ); + ASSERT(NT_SUCCESS(Status)); + + if (ARGUMENT_PRESENT( DebugParameter )) { + SmpDebug = DebugParameter; + } + + try { + Status = SmpInit( &InitialCommand, &ProcessHandles[ 0 ] ); + if (!NT_SUCCESS( Status )) { + KdPrint(( "SMSS: SmpInit return failure - Status == %x\n" )); + RtlInitUnicodeString( &UnicodeParameter, L"Session Manager Initialization" ); + Parameters[ 1 ] = (ULONG)Status; + } + else { + SYSTEM_FLAGS_INFORMATION FlagInfo; + + NtQuerySystemInformation( SystemFlagsInformation, + &FlagInfo, + sizeof( FlagInfo ), + NULL + ); + if (FlagInfo.Flags & (FLG_DEBUG_INITIAL_COMMAND | FLG_DEBUG_INITIAL_COMMAND_EX) ) { + DebugInitialCommand.MaximumLength = InitialCommand.Length + 64; + DebugInitialCommand.Length = 0; + DebugInitialCommand.Buffer = RtlAllocateHeap( RtlProcessHeap(), + MAKE_TAG( INIT_TAG ), + DebugInitialCommand.MaximumLength + ); + if (FlagInfo.Flags & FLG_ENABLE_CSRDEBUG) { + RtlAppendUnicodeToString( &DebugInitialCommand, L"ntsd -p -1 -d " ); + } + else { + RtlAppendUnicodeToString( &DebugInitialCommand, L"ntsd -d " ); + } + + if (FlagInfo.Flags & FLG_DEBUG_INITIAL_COMMAND_EX ) { + RtlAppendUnicodeToString( &DebugInitialCommand, L"-g -x " ); + } + + RtlAppendUnicodeStringToString( &DebugInitialCommand, &InitialCommand ); + InitialCommand = DebugInitialCommand; + } + + Status = SmpExecuteInitialCommand( &InitialCommand, &ProcessHandles[ 1 ] ); + if (NT_SUCCESS( Status )) { + Status = NtWaitForMultipleObjects( 2, + ProcessHandles, + WaitAny, + FALSE, + NULL + ); + } + + if (Status == STATUS_WAIT_0) { + RtlInitUnicodeString( &UnicodeParameter, L"Windows SubSystem" ); + Status = NtQueryInformationProcess( ProcessHandles[ 0 ], + ProcessBasicInformation, + &ProcessInfo, + sizeof( ProcessInfo ), + NULL + ); + + KdPrint(( "SMSS: Windows subsystem terminated when it wasn't supposed to.\n" )); + } + else { + RtlInitUnicodeString( &UnicodeParameter, L"Windows Logon Process" ); + if (Status == STATUS_WAIT_1) { + Status = NtQueryInformationProcess( ProcessHandles[ 1 ], + ProcessBasicInformation, + &ProcessInfo, + sizeof( ProcessInfo ), + NULL + ); + } + else { + ProcessInfo.ExitStatus = Status; + Status = STATUS_SUCCESS; + } + + KdPrint(( "SMSS: Initial command '%wZ' terminated when it wasn't supposed to.\n", &InitialCommand )); + } + + if (NT_SUCCESS( Status )) { + Parameters[ 1 ] = (ULONG)ProcessInfo.ExitStatus; + } + else { + Parameters[ 1 ] = (ULONG)STATUS_UNSUCCESSFUL; + } + } + } + except( SmpUnhandledExceptionFilter( GetExceptionInformation() ) ) { + RtlInitUnicodeString( &UnicodeParameter, L"Unhandled Exception in Session Manager" ); + Parameters[ 1 ] = (ULONG)GetExceptionCode(); + } + + // + // We are hosed, so raise a fata system error to shutdown the system. + // (Basically a user mode KeBugCheck). + // + + Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE, + (BOOLEAN)TRUE, + TRUE, + &WasEnabled + ); + + if (Status == STATUS_NO_TOKEN) { + + // + // No thread token, use the process token + // + + Status = RtlAdjustPrivilege( SE_SHUTDOWN_PRIVILEGE, + (BOOLEAN)TRUE, + FALSE, + &WasEnabled + ); + } + + Parameters[ 0 ] = (ULONG)&UnicodeParameter; + + Status = NtRaiseHardError( STATUS_SYSTEM_PROCESS_TERMINATED, + 2, + 1, + Parameters, + OptionShutdownSystem, + &Response + ); + + // + // If this returns, giveup + // + + NtTerminateProcess( NtCurrentProcess(), Status ); +} + + +EXCEPTION_DISPOSITION +SmpUnhandledExceptionFilter( + struct _EXCEPTION_POINTERS *ExceptionInfo + ) +{ +#if DBG + DbgPrint( "SMSS: Unhandled exception - Status == %x IP == %x\n", + ExceptionInfo->ExceptionRecord->ExceptionCode, + ExceptionInfo->ExceptionRecord->ExceptionAddress + ); + DbgPrint( " Memory Address: %x Read/Write: %x\n", + ExceptionInfo->ExceptionRecord->ExceptionInformation[ 0 ], + ExceptionInfo->ExceptionRecord->ExceptionInformation[ 1 ] + ); + + DbgBreakPoint(); +#endif + + return EXCEPTION_EXECUTE_HANDLER; +} diff --git a/private/sm/server/smss.rc b/private/sm/server/smss.rc new file mode 100644 index 000000000..9c81eee6c --- /dev/null +++ b/private/sm/server/smss.rc @@ -0,0 +1,10 @@ +#include <windows.h> +#include <ntverp.h> + +#define VER_FILETYPE VFT_APP +#define VER_FILESUBTYPE VFT2_UNKNOWN +#define VER_FILEDESCRIPTION_STR "Windows NT Session Manager" +#define VER_INTERNALNAME_STR "smss.exe" +#define VER_ORIGINALFILENAME_STR "smss.exe" + +#include "common.ver" diff --git a/private/sm/server/sources b/private/sm/server/sources new file mode 100644 index 000000000..bfa600bf8 --- /dev/null +++ b/private/sm/server/sources @@ -0,0 +1,57 @@ +!IF 0 + +Copyright (c) 1989 Microsoft Corporation + +Module Name: + + sources. + +Abstract: + + This file specifies the target component being built and the list of + sources files needed to build that component. Also specifies optional + compiler switches and libraries that are unique for the component being + built. + + +Author: + + Steve Wood (stevewo) 12-Apr-1990 + +NOTE: Commented description of this file is in \nt\bak\bin\sources.tpl + +!ENDIF + +MAJORCOMP=sm +MINORCOMP=server + +TARGETNAME=smss +TARGETPATH=obj +TARGETTYPE=PROGRAM + +INCLUDES=..\inc + +MSC_WARNING_LEVEL=/W3 /WX + +USE_NTDLL=1 + +BACKGROUND_USE=1 + +SOURCES=sminit.c \ + smloop.c \ + smsbapi.c \ + smsmapi.c \ + smsesnid.c \ + smdbg.c \ + dbginit.c \ + dbgloop.c \ + dbgssapi.c \ + dbguiapi.c \ + dbguisup.c \ + dbgapsup.c \ + smss.rc \ + smss.c \ + dbgdump.c + +UMTYPE=ntss +COFFBASE=smss |