summaryrefslogtreecommitdiffstats
path: root/private/sm
diff options
context:
space:
mode:
Diffstat (limited to 'private/sm')
-rw-r--r--private/sm/client/makefile6
-rw-r--r--private/sm/client/smcsup.c125
-rw-r--r--private/sm/client/smdllp.h30
-rw-r--r--private/sm/client/smstub.c213
-rw-r--r--private/sm/client/sources35
-rw-r--r--private/sm/dirs26
-rw-r--r--private/sm/inc/sm.h94
-rw-r--r--private/sm/server/dbgapsup.c236
-rw-r--r--private/sm/server/dbgdump.c80
-rw-r--r--private/sm/server/dbginit.c165
-rw-r--r--private/sm/server/dbgloop.c560
-rw-r--r--private/sm/server/dbgsrvp.h338
-rw-r--r--private/sm/server/dbgssapi.c704
-rw-r--r--private/sm/server/dbguiapi.c675
-rw-r--r--private/sm/server/dbguisup.c242
-rw-r--r--private/sm/server/makefile6
-rw-r--r--private/sm/server/smdbg.c124
-rw-r--r--private/sm/server/sminit.c4694
-rw-r--r--private/sm/server/smloop.c451
-rw-r--r--private/sm/server/smsbapi.c215
-rw-r--r--private/sm/server/smsesnid.c231
-rw-r--r--private/sm/server/smsmapi.c238
-rw-r--r--private/sm/server/smsrvp.h551
-rw-r--r--private/sm/server/smss.c206
-rw-r--r--private/sm/server/smss.rc10
-rw-r--r--private/sm/server/sources57
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