From dfb761830dbfa0ff7c9c41efbe60c1cab2788559 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Tue, 7 Feb 2012 07:13:42 +0000 Subject: [PATCH] [SMSS2]: Implement executing the initial command as well as doing the SM-to-SM initial connection. [SMSS2]: Implement the main LPC loop and handle all the supported APIs (all stubs for now). Also handle new connection requests and implement SmpHandleConnectionRequest. [SMSS2]: Implement subsystem helper functions. [SMSS2]: Use SmApiPort2 instead of Sm2ApiPort. [SMSS2]: Rename the SMSRV_APIs not to conflict with the function names, nor with the client functions in smlib. svn path=/trunk/; revision=55478 --- reactos/base/system/smss2/CMakeLists.txt | 2 +- reactos/base/system/smss2/sminit.c | 2 +- reactos/base/system/smss2/smloop.c | 355 +++++++++++++++++++++- reactos/base/system/smss2/smsessn.c | 33 +- reactos/base/system/smss2/smss.c | 121 +++++++- reactos/base/system/smss2/smss.h | 41 +++ reactos/base/system/smss2/smss2.rbuild | 1 + reactos/base/system/smss2/smsubsys.c | 91 ++++++ reactos/include/reactos/subsys/sm/smmsg.h | 39 ++- 9 files changed, 660 insertions(+), 25 deletions(-) diff --git a/reactos/base/system/smss2/CMakeLists.txt b/reactos/base/system/smss2/CMakeLists.txt index dfffa88aa0c..35dd1f81e5a 100644 --- a/reactos/base/system/smss2/CMakeLists.txt +++ b/reactos/base/system/smss2/CMakeLists.txt @@ -15,7 +15,7 @@ list(APPEND SOURCE add_executable(smss2 WIN32 ${SOURCE}) -target_link_libraries(smss2 nt pseh) +target_link_libraries(smss2 nt pseh smlib) add_pch(smss2 smss.h) diff --git a/reactos/base/system/smss2/sminit.c b/reactos/base/system/smss2/sminit.c index d05a84ce3de..3da3fce37a5 100644 --- a/reactos/base/system/smss2/sminit.c +++ b/reactos/base/system/smss2/sminit.c @@ -2439,7 +2439,7 @@ SmpInit(IN PUNICODE_STRING InitialCommand, RtlInitUnicodeString(&Os2Name, L"OS2"); /* Create the SM API Port */ - RtlInitUnicodeString(&PortName, L"\\Sm2ApiPort"); + RtlInitUnicodeString(&PortName, L"\\SmApiPort2"); InitializeObjectAttributes(&ObjectAttributes, &PortName, 0, NULL, NULL); Status = NtCreatePort(&PortHandle, &ObjectAttributes, diff --git a/reactos/base/system/smss2/smloop.c b/reactos/base/system/smss2/smloop.c index 574d7e8821e..ff05e7993f4 100644 --- a/reactos/base/system/smss2/smloop.c +++ b/reactos/base/system/smss2/smloop.c @@ -14,26 +14,365 @@ /* GLOBALS ********************************************************************/ +typedef struct _SMP_CLIENT_CONTEXT +{ + PVOID Subsystem; + HANDLE ProcessHandle; + HANDLE PortHandle; + ULONG dword10; +} SMP_CLIENT_CONTEXT, *PSMP_CLIENT_CONTEXT; + +typedef +NTSTATUS +(NTAPI *PSM_API_HANDLER)( + IN PSM_API_MSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT ClientContext, + IN HANDLE SmApiPort +); + +volatile LONG SmTotalApiThreads; +HANDLE SmUniqueProcessId; + +/* API HANDLERS ***************************************************************/ + +NTSTATUS +NTAPI +SmpCreateForeignSession(IN PSM_API_MSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT ClientContext, + IN HANDLE SmApiPort) +{ + DPRINT1("%s is not yet implemented\n", __FUNCTION__); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +SmpSessionComplete(IN PSM_API_MSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT ClientContext, + IN HANDLE SmApiPort) +{ + DPRINT1("%s is not yet implemented\n", __FUNCTION__); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +SmpTerminateForeignSession(IN PSM_API_MSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT ClientContext, + IN HANDLE SmApiPort) +{ + DPRINT1("%s is not yet implemented\n", __FUNCTION__); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +SmpExecPgm(IN PSM_API_MSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT ClientContext, + IN HANDLE SmApiPort) +{ + DPRINT1("%s is not yet implemented\n", __FUNCTION__); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +SmpLoadDeferedSubsystem(IN PSM_API_MSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT ClientContext, + IN HANDLE SmApiPort) +{ + DPRINT1("%s is not yet implemented\n", __FUNCTION__); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +SmpStartCsr(IN PSM_API_MSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT ClientContext, + IN HANDLE SmApiPort) +{ + DPRINT1("%s is not yet implemented\n", __FUNCTION__); + return STATUS_SUCCESS; +} + +NTSTATUS +NTAPI +SmpStopCsr(IN PSM_API_MSG SmApiMsg, + IN PSMP_CLIENT_CONTEXT ClientContext, + IN HANDLE SmApiPort) +{ + DPRINT1("%s is not yet implemented\n", __FUNCTION__); + return STATUS_SUCCESS; +} + +PSM_API_HANDLER SmpApiDispatch[SmMaxApiNumber] = +{ + SmpCreateForeignSession, + SmpSessionComplete, + SmpTerminateForeignSession, + SmpExecPgm, + SmpLoadDeferedSubsystem, + SmpStartCsr, + SmpStopCsr +}; + /* FUNCTIONS ******************************************************************/ +NTSTATUS +NTAPI +SmpHandleConnectionRequest(IN HANDLE SmApiPort, + IN PSB_API_MSG SbApiMsg) +{ + BOOLEAN Accept = TRUE; + HANDLE PortHandle, ProcessHandle; + ULONG SessionId; + UNICODE_STRING SubsystemPort; + SMP_CLIENT_CONTEXT *ClientContext; + NTSTATUS Status; + OBJECT_ATTRIBUTES ObjectAttributes; + REMOTE_PORT_VIEW PortView; + SECURITY_QUALITY_OF_SERVICE SecurityQos; + PSMP_SUBSYSTEM CidSubsystem, TypeSubsystem; + + /* Initialize QoS data */ + SecurityQos.ImpersonationLevel = SecurityIdentification; + SecurityQos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING; + SecurityQos.EffectiveOnly = TRUE; + + /* Check if this is SM connecting to itself */ + if (SbApiMsg->h.ClientId.UniqueProcess == SmUniqueProcessId) + { + /* No need to get any handle -- assume session 0 */ + DPRINT1("SM connecting to SM\n"); + ProcessHandle = NULL; + SessionId = 0; + } + else + { + /* Reference the foreign process */ + DPRINT1("Incoming request from %lx\n", SbApiMsg->h.ClientId.UniqueProcess); + InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); + Status = NtOpenProcess(&ProcessHandle, + PROCESS_QUERY_INFORMATION, + &ObjectAttributes, + &SbApiMsg->h.ClientId); + if (!NT_SUCCESS(Status)) Accept = FALSE; + + /* Get its session ID */ + SmpGetProcessMuSessionId(ProcessHandle, &SessionId); + } + + /* See if we already know about the caller's subystem */ + CidSubsystem = SmpLocateKnownSubSysByCid(&SbApiMsg->h.ClientId); + if ((CidSubsystem) && (Accept)) + { + /* Check if we already have a subsystem for this kind of image */ + TypeSubsystem = SmpLocateKnownSubSysByType(SessionId, + SbApiMsg->ConnectionInfo.SubsystemType); + if (TypeSubsystem == CidSubsystem) + { + /* Someone is trying to take control of an existing subsystem, fail */ + Accept = FALSE; + DPRINT1("SMSS: Connection from SubSystem rejected\n"); + DPRINT1("SMSS: Image type already being served\n"); + } + else + { + /* Set this image type as the type for this subsystem */ + CidSubsystem->ImageType = SbApiMsg->ConnectionInfo.SubsystemType; + } + + /* Drop the reference we had acquired */ + if (TypeSubsystem) SmpDereferenceSubsystem(TypeSubsystem); + } + + /* Check if we'll be accepting the connection */ + if (Accept) + { + /* We will, so create a client context for it */ + ClientContext = RtlAllocateHeap(SmpHeap, 0, sizeof(SMP_CLIENT_CONTEXT)); + if (ClientContext) + { + ClientContext->ProcessHandle = ProcessHandle; + ClientContext->Subsystem = CidSubsystem; + ClientContext->dword10 = 0; + ClientContext->PortHandle = NULL; + } + else + { + /* Failed to allocate a client context, so reject the connection */ + DPRINT1("Rejecting connectiond due to lack of memory\n"); + Accept = FALSE; + } + } + else + { + /* Use a bogus context since we're going to reject the message */ + ClientContext = (PSMP_CLIENT_CONTEXT)SbApiMsg; + } + + /* Now send the actual accept reply (which could be a rejection) */ + PortView.Length = sizeof(PortView); + DPRINT1("Accepting: %d connection with context: %p\n", Accept, ClientContext); + Status = NtAcceptConnectPort(&PortHandle, + ClientContext, + &SbApiMsg->h, + Accept, + NULL, + &PortView); + if (!(Accept) || !(NT_SUCCESS(Status))) + { + /* Close the process handle, reference the subsystem, and exit */ + DPRINT1("Accept failed or rejected: %lx\n", Status); + if (ClientContext != (PVOID)SbApiMsg) RtlFreeHeap(SmpHeap, 0, ClientContext); + if (ProcessHandle) NtClose(ProcessHandle); + if (CidSubsystem) SmpDereferenceSubsystem(CidSubsystem); + return Status; + } + + /* Save the port handle now that we've accepted it */ + if (ClientContext) ClientContext->PortHandle = PortHandle; + if (CidSubsystem) CidSubsystem->PortHandle = PortHandle; + + /* Complete the port connection */ + Status = NtCompleteConnectPort(PortHandle); + if ((NT_SUCCESS(Status)) && (CidSubsystem)) + { + /* This was an actual subsystem, so connect back to it */ + DPRINT1("Connecting back to %wZ\n", &SubsystemPort); + SbApiMsg->ConnectionInfo.SbApiPortName[119] = UNICODE_NULL; + RtlCreateUnicodeString(&SubsystemPort, + SbApiMsg->ConnectionInfo.SbApiPortName); + Status = NtConnectPort(&CidSubsystem->SbApiPort, + &SubsystemPort, + &SecurityQos, + NULL, + NULL, + NULL, + NULL, + NULL); + if (!NT_SUCCESS(Status)) + { + DPRINT1("SMSS: Connect back to Sb %wZ failed %lx\n", &SubsystemPort, Status); + } + RtlFreeUnicodeString(&SubsystemPort); + + /* Now that we're connected, signal the event handle */ + NtSetEvent(CidSubsystem->Event, NULL); + } + else if (CidSubsystem) + { + /* We failed to complete the connection, so clear the port handle */ + DPRINT1("Completing the connection failed: %lx\n", Status); + CidSubsystem->PortHandle = NULL; + } + + /* Dereference the subsystem and return the result */ + if (CidSubsystem) SmpDereferenceSubsystem(CidSubsystem); + return Status; +} + ULONG NTAPI SmpApiLoop(IN PVOID Parameter) { HANDLE SmApiPort = (HANDLE)Parameter; NTSTATUS Status; - PVOID ClientContext; - PSM_API_MSG RequestMsg = NULL; - SM_API_MSG ReplyMsg; + PSMP_CLIENT_CONTEXT ClientContext; + PSM_API_MSG ReplyMsg = NULL; + SM_API_MSG RequestMsg; + PROCESS_BASIC_INFORMATION ProcessInformation; + LARGE_INTEGER Timeout; - DPRINT1("API Loop: %p\n", SmApiPort); + /* Increase the number of API threads for throttling code for later */ + _InterlockedExchangeAdd(&SmTotalApiThreads, 1); + + /* Mark us critical */ + RtlSetThreadIsCritical(TRUE, NULL, TRUE); + + /* Set the PID of the SM process itself for later checking */ + NtQueryInformationProcess(NtCurrentProcess(), + ProcessBasicInformation, + &ProcessInformation, + sizeof(ProcessInformation), + NULL); + SmUniqueProcessId = (HANDLE)ProcessInformation.UniqueProcessId; + + /* Now process incoming messages */ while (TRUE) { + /* Begin waiting on a request */ + DPRINT1("API Loop: %p\n", SmApiPort); Status = NtReplyWaitReceivePort(SmApiPort, - &ClientContext, - &RequestMsg->h, - &ReplyMsg.h); - DPRINT1("API loop returned: %lx\n", Status); + (PVOID*)&ClientContext, + &ReplyMsg->h, + &RequestMsg.h); + if (Status == STATUS_NO_MEMORY) + { + /* Ran out of memory, so do a little timeout and try again */ + if (ReplyMsg) DPRINT1("SMSS: Failed to reply to calling thread, retrying.\n"); + Timeout.QuadPart = -50000000; + NtDelayExecution(FALSE, &Timeout); + continue; + } + + /* Check what kind of request we received */ + switch (RequestMsg.h.u2.s2.Type) + { + /* A new connection */ + case LPC_CONNECTION_REQUEST: + /* Create the right structures for it */ + DPRINT1("New connection request\n"); + SmpHandleConnectionRequest(SmApiPort, (PSB_API_MSG)&RequestMsg); + ReplyMsg = NULL; + break; + + /* A closed connection */ + case LPC_PORT_CLOSED: + /* Destroy any state we had for this client */ + DPRINT1("Port closed\n"); + //if (ClientContext) SmpPushDeferredClientContext(ClientContext); + ReplyMsg = NULL; + break; + + /* An actual API message */ + default: + if (!ClientContext) + { + ReplyMsg = NULL; + break; + } + + RequestMsg.ReturnValue = STATUS_PENDING; + + /* Check if the API is valid */ + if (RequestMsg.ApiNumber >= SmMaxApiNumber) + { + /* It isn't, fail */ + DPRINT1("Invalid API: %lx\n", RequestMsg.ApiNumber); + Status = STATUS_NOT_IMPLEMENTED; + } + else if ((RequestMsg.ApiNumber <= SmTerminateForeignSessionApi) && + !(ClientContext->Subsystem)) + { + /* It's valid, but doesn't have a subsystem with it */ + DPRINT1("Invalid session API\n"); + Status = STATUS_INVALID_PARAMETER; + } + else + { + /* It's totally okay, so call the dispatcher for it */ + DPRINT1("Calling dispatcher for ID: %lx\n", RequestMsg.ApiNumber); + Status = SmpApiDispatch[RequestMsg.ApiNumber](&RequestMsg, + ClientContext, + SmApiPort); + } + + /* Write the result valud and return the message back */ + RequestMsg.ReturnValue = Status; + ReplyMsg = &RequestMsg; + break; + } } return STATUS_SUCCESS; } diff --git a/reactos/base/system/smss2/smsessn.c b/reactos/base/system/smss2/smsessn.c index 4c12563cb2f..c8d44558013 100644 --- a/reactos/base/system/smss2/smsessn.c +++ b/reactos/base/system/smss2/smsessn.c @@ -23,6 +23,37 @@ HANDLE SmpSessionsObjectDirectory; /* FUNCTIONS ******************************************************************/ +NTSTATUS +NTAPI +SmpGetProcessMuSessionId(IN HANDLE ProcessHandle, + OUT PULONG SessionId) +{ + NTSTATUS Status; + ULONG ProcessSession; + + /* Query the kernel for the session ID */ + Status = NtQueryInformationProcess(ProcessHandle, + ProcessSessionInformation, + &ProcessSession, + sizeof(ProcessSession), + NULL); + if (NT_SUCCESS(Status)) + { + /* Copy it back into the buffer */ + *SessionId = ProcessSession; + } + else + { + /* Failure -- assume session zero */ + DPRINT1("SMSS: GetProcessMuSessionId, Process=%x, Status=%x\n", + ProcessHandle, Status); + *SessionId = 0; + } + + /* Return result */ + return Status; +} + NTSTATUS NTAPI SmpSetProcessMuSessionId(IN HANDLE ProcessHandle, @@ -30,7 +61,7 @@ SmpSetProcessMuSessionId(IN HANDLE ProcessHandle, { NTSTATUS Status; - /* Tell the kernel about our session ID */ + /* Tell the kernel about the session ID */ Status = NtSetInformationProcess(ProcessHandle, ProcessSessionInformation, &SessionId, diff --git a/reactos/base/system/smss2/smss.c b/reactos/base/system/smss2/smss.c index bfcd52f9418..dd6688f9504 100644 --- a/reactos/base/system/smss2/smss.c +++ b/reactos/base/system/smss2/smss.c @@ -29,6 +29,8 @@ ULONG NtInitialUserProcessBufferType = REG_SZ; UNICODE_STRING SmpSystemRoot; ULONG AttachedSessionId = -1; BOOLEAN SmpDebug, SmpEnableDots; +HANDLE SmApiPort; +HANDLE SmpInitialCommandProcessId; /* FUNCTIONS ******************************************************************/ @@ -57,6 +59,7 @@ SmpExecuteImage(IN PUNICODE_STRING FileName, NTSTATUS Status; RTL_USER_PROCESS_INFORMATION LocalProcessInfo; PRTL_USER_PROCESS_PARAMETERS ProcessParameters; + DPRINT1("Executing image: %wZ\n", FileName); /* Use the input process information if we have it, otherwise use local */ ProcessInfo = ProcessInformation; @@ -295,6 +298,103 @@ SmpExecuteCommand(IN PUNICODE_STRING CommandLine, return Status; } +NTSTATUS +NTAPI +SmpExecuteInitialCommand(IN ULONG MuSessionId, + IN PUNICODE_STRING InitialCommand, + IN HANDLE InitialCommandProcess, + OUT PHANDLE ReturnPid) +{ + NTSTATUS Status; + RTL_USER_PROCESS_INFORMATION ProcessInfo; + UNICODE_STRING Arguments, ImageFileDirectory, ImageFileName; + ULONG Flags = 0; + + /* Check if we haven't yet connected to ourselves */ + if (!SmApiPort) + { + /* Connect to ourselves, as a client */ + Status = SmConnectToSm(0, 0, 0, &SmApiPort); + if (!NT_SUCCESS(Status)) + { + DPRINT1("SMSS: Unable to connect to SM - Status == %lx\n", Status); + return Status; + } + } + + /* Parse the initial command line */ + Status = SmpParseCommandLine(InitialCommand, + (PULONG)&Flags, + &ImageFileName, + &ImageFileDirectory, + &Arguments); + if (Flags & SMP_INVALID_PATH) + { + /* Fail if it doesn't exist */ + DPRINT1("SMSS: Initial command image (%wZ) not found\n", &ImageFileName); + if (ImageFileName.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, ImageFileName.Buffer); + return STATUS_OBJECT_NAME_NOT_FOUND; + } + + /* And fail if any other reason is also true */ + if (!NT_SUCCESS(Status)) + { + DPRINT1("SMSS: SmpParseCommand( %wZ ) failed - Status == %lx\n", + InitialCommand, Status); + return Status; + } + + /* Execute the initial command -- but defer its full execution */ + Status = SmpExecuteImage(&ImageFileName, + &ImageFileDirectory, + InitialCommand, + MuSessionId, + SMP_DEFERRED_FLAG, + &ProcessInfo); + + /* Free any buffers we had lying around */ + if (ImageFileName.Buffer) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, ImageFileName.Buffer); + } + if (ImageFileDirectory.Buffer) + { + RtlFreeHeap(RtlGetProcessHeap(), 0, ImageFileDirectory.Buffer); + } + if (Arguments.Buffer) RtlFreeHeap(RtlGetProcessHeap(), 0, Arguments.Buffer); + + /* Bail out if we couldn't execute the initial command */ + if (!NT_SUCCESS(Status)) return Status; + + /* Now duplicate the handle to this process */ + Status = NtDuplicateObject(NtCurrentProcess(), + ProcessInfo.ProcessHandle, + NtCurrentProcess(), + InitialCommandProcess, + PROCESS_ALL_ACCESS, + 0, + 0); + if (!NT_SUCCESS(Status)) + { + /* Kill it utterly if duplication failed */ + DPRINT1("SMSS: DupObject Failed. Status == %lx\n", Status); + NtTerminateProcess(ProcessInfo.ProcessHandle, Status); + NtResumeThread(ProcessInfo.ThreadHandle, NULL); + NtClose(ProcessInfo.ThreadHandle); + NtClose(ProcessInfo.ProcessHandle); + return Status; + } + + /* Return PID to the caller, and set this as the initial command PID */ + if (ReturnPid) *ReturnPid = ProcessInfo.ClientId.UniqueProcess; + if (!MuSessionId) SmpInitialCommandProcessId = ProcessInfo.ClientId.UniqueProcess; + + /* Now call our server execution function to wrap up its initialization */ + Status = SmExecPgm(SmApiPort, &ProcessInfo, FALSE); + if (!NT_SUCCESS(Status)) DPRINT1("SMSS: SmExecPgm Failed. Status == %lx\n", Status); + return Status; +} + NTSTATUS NTAPI ExpLoadInitialProcess(IN PINIT_BUFFER InitBuffer, @@ -630,6 +730,9 @@ _main(IN INT argc, DPRINT1("SMSS: SmpInit return failure - Status == %x\n", Status); RtlInitUnicodeString(&DbgString, L"Session Manager Initialization"); Parameters[1] = Status; + DPRINT1("SMSS-2 Loaded... Launching original SMSS\n"); + Status = LaunchOldSmss(Handles); + goto SetupHack; //_SEH2_LEAVE; Hack so that setup can work. will go away later } @@ -647,14 +750,21 @@ _main(IN INT argc, DPRINT1("Global Flags Set to SMSS Debugging: Not yet supported\n"); } -#if 0 - /* Execute the initial command (Winlogon.exe) */ - Status = SmpExecuteInitialCommand(0, &InitialCommand, &Handles[1], NULL); -#else /* Launch the original SMSS */ DPRINT1("SMSS-2 Loaded... Launching original SMSS\n"); Status = LaunchOldSmss(Handles); -#endif + if (!NT_SUCCESS(Status)) + { + /* Fail and raise a hard error */ + DPRINT1("SMSS: Execute Old SMSS failed\n"); + RtlInitUnicodeString(&DbgString, + L"Session Manager LaunchOldSmss"); + Parameters[1] = Status; + _SEH2_LEAVE; + } + + /* Execute the initial command (Winlogon.exe) */ + Status = SmpExecuteInitialCommand(0, &InitialCommand, &Handles[1], NULL); if (!NT_SUCCESS(Status)) { /* Fail and raise a hard error */ @@ -679,6 +789,7 @@ _main(IN INT argc, SmpReleasePrivilege(State); /* Wait on either CSRSS or Winlogon to die */ +SetupHack: Status = NtWaitForMultipleObjects(RTL_NUMBER_OF(Handles), Handles, WaitAny, diff --git a/reactos/base/system/smss2/smss.h b/reactos/base/system/smss2/smss.h index afbf5508eb2..22b8af81d3b 100644 --- a/reactos/base/system/smss2/smss.h +++ b/reactos/base/system/smss2/smss.h @@ -49,6 +49,20 @@ typedef struct _SMP_REGISTRY_VALUE PCHAR AnsiValue; } SMP_REGISTRY_VALUE, *PSMP_REGISTRY_VALUE; +typedef struct _SMP_SUBSYSTEM +{ + LIST_ENTRY Entry; + HANDLE Event; + HANDLE ProcessHandle; + ULONG ImageType; + HANDLE PortHandle; + HANDLE SbApiPort; + CLIENT_ID ClientId; + ULONG MuSessionId; + BOOLEAN Terminating; + ULONG ReferenceCount; +} SMP_SUBSYSTEM, *PSMP_SUBSYSTEM; + /* EXTERNALS ******************************************************************/ extern RTL_CRITICAL_SECTION SmpKnownSubSysLock; @@ -209,4 +223,31 @@ NTAPI SmpTranslateSystemPartitionInformation( VOID ); + +PSMP_SUBSYSTEM +NTAPI +SmpLocateKnownSubSysByCid( + IN PCLIENT_ID ClientId +); + +PSMP_SUBSYSTEM +NTAPI +SmpLocateKnownSubSysByType( + IN ULONG MuSessionId, + IN ULONG ImageType +); + +NTSTATUS +NTAPI +SmpGetProcessMuSessionId( + IN HANDLE ProcessHandle, + OUT PULONG SessionId +); + +VOID +NTAPI +SmpDereferenceSubsystem( + IN PSMP_SUBSYSTEM SubSystem +); + #endif diff --git a/reactos/base/system/smss2/smss2.rbuild b/reactos/base/system/smss2/smss2.rbuild index 7c01ba71e53..23e97ccb97a 100644 --- a/reactos/base/system/smss2/smss2.rbuild +++ b/reactos/base/system/smss2/smss2.rbuild @@ -7,6 +7,7 @@ nt pseh ntdll + smlib smss.h smss.c diff --git a/reactos/base/system/smss2/smsubsys.c b/reactos/base/system/smss2/smsubsys.c index 16c407a5f6d..459b2bf16b7 100644 --- a/reactos/base/system/smss2/smsubsys.c +++ b/reactos/base/system/smss2/smsubsys.c @@ -23,6 +23,97 @@ WCHAR InitialCommandBuffer[256]; /* FUNCTIONS ******************************************************************/ +VOID +NTAPI +SmpDereferenceSubsystem(IN PSMP_SUBSYSTEM SubSystem) +{ + /* Acquire the database lock while we (potentially) destroy this subsystem */ + RtlEnterCriticalSection(&SmpKnownSubSysLock); + + /* Drop the reference and see if it's terminating */ + if (!(--SubSystem->ReferenceCount) && (SubSystem->Terminating)) + { + /* Close all handles and free it */ + if (SubSystem->Event) NtClose(SubSystem->Event); + if (SubSystem->ProcessHandle) NtClose(SubSystem->ProcessHandle); + if (SubSystem->SbApiPort) NtClose(SubSystem->SbApiPort); + RtlFreeHeap(SmpHeap, 0, SubSystem); + } + + /* Release the database lock */ + RtlLeaveCriticalSection(&SmpKnownSubSysLock); +} + +PSMP_SUBSYSTEM +NTAPI +SmpLocateKnownSubSysByCid(IN PCLIENT_ID ClientId) +{ + PSMP_SUBSYSTEM Subsystem = NULL; + PLIST_ENTRY NextEntry; + + /* Lock the subsystem database */ + RtlEnterCriticalSection(&SmpKnownSubSysLock); + + /* Loop each subsystem in the database */ + NextEntry = SmpKnownSubSysHead.Flink; + while (NextEntry != &SmpKnownSubSysHead) + { + /* Check if this one matches the client ID and is still valid */ + Subsystem = CONTAINING_RECORD(NextEntry, SMP_SUBSYSTEM, Entry); + if ((*(PULONGLONG)&Subsystem->ClientId == *(PULONGLONG)&ClientId) && + !(Subsystem->Terminating)) + { + /* Add a reference and return it */ + Subsystem->ReferenceCount++; + break; + } + + /* Reset the current pointer and keep earching */ + Subsystem = NULL; + NextEntry = NextEntry->Flink; + } + + /* Release the lock and return the subsystem we found */ + RtlLeaveCriticalSection(&SmpKnownSubSysLock); + return Subsystem; +} + +PSMP_SUBSYSTEM +NTAPI +SmpLocateKnownSubSysByType(IN ULONG MuSessionId, + IN ULONG ImageType) +{ + PSMP_SUBSYSTEM Subsystem = NULL; + PLIST_ENTRY NextEntry; + + /* Lock the subsystem database */ + RtlEnterCriticalSection(&SmpKnownSubSysLock); + + /* Loop each subsystem in the database */ + NextEntry = SmpKnownSubSysHead.Flink; + while (NextEntry != &SmpKnownSubSysHead) + { + /* Check if this one matches the image and uID, and is still valid */ + Subsystem = CONTAINING_RECORD(NextEntry, SMP_SUBSYSTEM, Entry); + if ((Subsystem->ImageType == ImageType) && + !(Subsystem->Terminating) && + (Subsystem->MuSessionId == MuSessionId)) + { + /* Return it referenced for the caller */ + Subsystem->ReferenceCount++; + break; + } + + /* Reset the current pointer and keep earching */ + Subsystem = NULL; + NextEntry = NextEntry->Flink; + } + + /* Release the lock and return the subsystem we found */ + RtlLeaveCriticalSection(&SmpKnownSubSysLock); + return Subsystem; +} + NTSTATUS NTAPI SmpLoadSubSystem(IN PUNICODE_STRING FileName, diff --git a/reactos/include/reactos/subsys/sm/smmsg.h b/reactos/include/reactos/subsys/sm/smmsg.h index 6395fb89751..0356a969f2b 100644 --- a/reactos/include/reactos/subsys/sm/smmsg.h +++ b/reactos/include/reactos/subsys/sm/smmsg.h @@ -21,14 +21,14 @@ // typedef enum _SMSRV_API_NUMBER { - SmpCreateForeignSession, - SmpSessionComplete, - SmpTerminateForeignSession, - SmpExecPgm, - SmpLoadDeferedSubsystem, - SmpStartCsr, - SmpStopCsr, - SmpMaxApiNumber // Based on BasepMaxApiNumber, UserpMaxApiNumber... + SmCreateForeignSessionApi, + SmSessionCompleteApi, + SmTerminateForeignSessionApi, + SmExecPgmApi, + SmLoadDeferedSubsystemApi, + SmStartCsrApi, + SmStopCsrApi, + SmMaxApiNumber // Based on BasepMaxApiNumber, UserpMaxApiNumber... } SMSRV_API_NUMBER; // @@ -184,7 +184,7 @@ typedef struct _SB_CONNECTION_INFO // typedef struct _SB_API_MSG { - PORT_MESSAGE Header; + PORT_MESSAGE h; union { SB_CONNECTION_INFO ConnectionInfo; @@ -208,4 +208,25 @@ typedef struct _SB_API_MSG // C_ASSERT(sizeof(SB_CONNECTION_INFO) == 0xF4); C_ASSERT(sizeof(SB_API_MSG) == 0x110); + +// +// The actual server functions that a client linking with smlib can call +// +NTSTATUS +NTAPI +SmConnectToSm( + IN PUNICODE_STRING SbApiPortName, + IN HANDLE SbApiPort, + IN ULONG ImageType, + IN HANDLE SmApiPort +); + +NTSTATUS +NTAPI +SmExecPgm( + IN HANDLE SmApiPort, + IN PRTL_USER_PROCESS_INFORMATION ProcessInformation, + IN BOOLEAN DebugFlag +); + #endif