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 */ ProcessHandle = NULL; SessionId = 0; } else { /* Reference the foreign process */ 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); 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 */ 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; }
NTSTATUS NTAPI SmpSbCreateSession(IN PVOID Reserved, IN PSMP_SUBSYSTEM OtherSubsystem, IN PRTL_USER_PROCESS_INFORMATION ProcessInformation, IN ULONG MuSessionId, IN PCLIENT_ID DbgClientId) { NTSTATUS Status; PSMP_SUBSYSTEM KnownSubsys; SB_API_MSG SbApiMsg; ULONG SessionId; PSB_CREATE_SESSION_MSG CreateSessionMsg; /* Write out the create session message including its initial process */ CreateSessionMsg = &SbApiMsg.CreateSession; CreateSessionMsg->ProcessInfo = *ProcessInformation; CreateSessionMsg->MuSessionId = MuSessionId; if (DbgClientId) { CreateSessionMsg->ClientId = *DbgClientId; } else { CreateSessionMsg->ClientId.UniqueThread = NULL; CreateSessionMsg->ClientId.UniqueProcess = NULL; } /* Find a subsystem responsible for this session */ SmpGetProcessMuSessionId(ProcessInformation->ProcessHandle, &MuSessionId); if (!SmpCheckDuplicateMuSessionId(MuSessionId)) { NtClose(ProcessInformation->ProcessHandle); NtClose(ProcessInformation->ThreadHandle); DPRINT1("SMSS: CreateSession status=%x\n", STATUS_OBJECT_NAME_NOT_FOUND); return STATUS_OBJECT_NAME_NOT_FOUND; } /* Find the subsystem we have for this initial process */ KnownSubsys = SmpLocateKnownSubSysByType(MuSessionId, ProcessInformation-> ImageInformation.SubSystemType); if (KnownSubsys) { /* Duplicate the process handle into the message */ Status = NtDuplicateObject(NtCurrentProcess(), ProcessInformation->ProcessHandle, KnownSubsys->ProcessHandle, &CreateSessionMsg->ProcessInfo.ProcessHandle, PROCESS_ALL_ACCESS, 0, 0); if (NT_SUCCESS(Status)) { /* Duplicate the thread handle into the message */ Status = NtDuplicateObject(NtCurrentProcess(), ProcessInformation->ThreadHandle, KnownSubsys->ProcessHandle, &CreateSessionMsg->ProcessInfo.ThreadHandle, THREAD_ALL_ACCESS, 0, 0); if (!NT_SUCCESS(Status)) { /* Close everything on failure */ NtClose(ProcessInformation->ProcessHandle); NtClose(ProcessInformation->ThreadHandle); SmpDereferenceSubsystem(KnownSubsys); DbgPrint("SmpSbCreateSession: NtDuplicateObject (Thread) Failed %lx\n", Status); return Status; } /* Close the original handles as they are no longer needed */ NtClose(ProcessInformation->ProcessHandle); NtClose(ProcessInformation->ThreadHandle); /* Finally, allocate a new SMSS session ID for this session */ SessionId = SmpAllocateSessionId(KnownSubsys, OtherSubsystem); CreateSessionMsg->SessionId = SessionId; /* Fill out the LPC message header and send it to the client! */ SbApiMsg.ApiNumber = SbpCreateSession; SbApiMsg.h.u2.ZeroInit = 0; SbApiMsg.h.u1.s1.DataLength = sizeof(SB_CREATE_SESSION_MSG) + 8; SbApiMsg.h.u1.s1.TotalLength = sizeof(SbApiMsg); Status = NtRequestWaitReplyPort(KnownSubsys->SbApiPort, &SbApiMsg.h, &SbApiMsg.h); if (!NT_SUCCESS(Status)) { /* Bail out */ DPRINT1("SmpSbCreateSession: NtRequestWaitReply Failed %lx\n", Status); } else { /* If the API succeeded, get the result value from the LPC */ Status = SbApiMsg.ReturnValue; } /* Delete the session on any kind of failure */ if (!NT_SUCCESS(Status)) SmpDeleteSession(SessionId); } else { /* Close the handles on failure */ DPRINT1("SmpSbCreateSession: NtDuplicateObject (Process) Failed %lx\n", Status); NtClose(ProcessInformation->ProcessHandle); NtClose(ProcessInformation->ThreadHandle); } /* Dereference the subsystem and return the status of the LPC call */ SmpDereferenceSubsystem(KnownSubsys); return Status; } /* If we don't yet have a subsystem, only native images can be launched */ if (ProcessInformation->ImageInformation.SubSystemType != IMAGE_SUBSYSTEM_NATIVE) { /* Fail */ DPRINT1("SMSS: %s SubSystem has not been started.\n", SmpSubSystemNames[ProcessInformation->ImageInformation.SubSystemType]); Status = STATUS_UNSUCCESSFUL; NtClose(ProcessInformation->ProcessHandle); NtClose(ProcessInformation->ThreadHandle); return Status; } #if 0 /* This code handles debug applications, but it seems vestigial... */ if ((*(ULONGLONG)&CreateSessionMsg.ClientId) && (SmpDbgSsLoaded)) { Process = RtlAllocateHeap(SmpHeap, SmBaseTag, sizeof(SMP_PROCESS)); if (!Process) { DPRINT1("Unable to initialize debugging for Native App %lx.%lx -- out of memory\n", ProcessInformation->ClientId.UniqueProcess, ProcessInformation->ClientId.UniqueThread); NtClose(ProcessInformation->ProcessHandle); NtClose(ProcessInformation->ThreadHandle); return STATUS_NO_MEMORY; } Process->DbgClientId = CreateSessionMsg->ClientId; Process->ClientId = ProcessInformation->ClientId; InsertHeadList(&NativeProcessList, &Process->Entry); DPRINT1("Native Debug App %lx.%lx\n", Process->ClientId.UniqueProcess, Process->ClientId.UniqueThread); Status = NtSetInformationProcess(ProcessInformation->ProcessHandle, 7, &SmpDebugPort, 4); ASSERT(NT_SUCCESS(Status)); } #endif /* This is a native application being started as the initial command */ DPRINT1("Subsystem active, starting thread\n"); NtClose(ProcessInformation->ProcessHandle); NtResumeThread(ProcessInformation->ThreadHandle, NULL); NtClose(ProcessInformation->ThreadHandle); return STATUS_SUCCESS; }