/*++ * @name CsrRemoveProcess * * The CsrRemoveProcess function undoes a CsrInsertProcess operation and * removes the CSR Process from the Process List and notifies Server DLLs * of this removal. * * @param CsrProcess * Pointer to the CSR Process to remove. * * @return None. * * @remarks None. * *--*/ VOID NTAPI CsrRemoveProcess(IN PCSR_PROCESS CsrProcess) { PCSR_SERVER_DLL ServerDll; ULONG i; ASSERT(ProcessStructureListLocked()); /* Remove us from the Process List */ RemoveEntryList(&CsrProcess->ListLink); /* Release the lock */ CsrReleaseProcessLock(); /* Loop every Server DLL */ for (i = 0; i < CSR_SERVER_DLL_MAX; i++) { /* Get the Server DLL */ ServerDll = CsrLoadedServerDll[i]; /* Check if it's valid and if it has a Disconnect Callback */ if (ServerDll && ServerDll->DisconnectCallback) { /* Call it */ ServerDll->DisconnectCallback(CsrProcess); } } }
/*++ * @name CsrUnlockProcess * @implemented NT4 * * The CsrUnlockProcess undoes a previous CsrLockProcessByClientId operation. * * @param CsrProcess * Pointer to a previously locked CSR Process. * * @return STATUS_SUCCESS. * * @remarks This routine must be called with the Process Lock held. * *--*/ NTSTATUS NTAPI CsrUnlockProcess(IN PCSR_PROCESS CsrProcess) { /* Dereference the process */ CsrLockedDereferenceProcess(CsrProcess); /* Release the lock and return */ CsrReleaseProcessLock(); return STATUS_SUCCESS; }
/*++ * @name CsrLockProcessByClientId * @implemented NT4 * * The CsrLockProcessByClientId routine locks the CSR Process corresponding * to the given Process ID and optionally returns it. * * @param Pid * Process ID corresponding to the CSR Process which will be locked. * * @param CsrProcess * Optional pointer to a CSR Process pointer which will hold the * CSR Process corresponding to the given Process ID. * * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise. * * @remarks Locking a CSR Process is defined as acquiring an extra * reference to it and returning with the Process Lock held. * *--*/ NTSTATUS NTAPI CsrLockProcessByClientId(IN HANDLE Pid, OUT PCSR_PROCESS *CsrProcess) { PLIST_ENTRY NextEntry; PCSR_PROCESS CurrentProcess = NULL; NTSTATUS Status = STATUS_UNSUCCESSFUL; /* Acquire the lock */ CsrAcquireProcessLock(); /* Assume failure */ ASSERT(CsrProcess != NULL); *CsrProcess = NULL; /* Setup the List Pointers */ NextEntry = &CsrRootProcess->ListLink; do { /* Get the Process */ CurrentProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink); /* Check for PID Match */ if (CurrentProcess->ClientId.UniqueProcess == Pid) { Status = STATUS_SUCCESS; break; } /* Move to the next entry */ NextEntry = NextEntry->Flink; } while (NextEntry != &CsrRootProcess->ListLink); /* Check if we didn't find it in the list */ if (!NT_SUCCESS(Status)) { /* Nothing found, release the lock */ CsrReleaseProcessLock(); } else { /* Lock the found process and return it */ CsrLockedReferenceProcess(CurrentProcess); *CsrProcess = CurrentProcess; } /* Return the result */ return Status; }
/*++ * @name CsrDereferenceWait * @implemented NT4 * * The CsrDereferenceWait routine derefences a CSR Wait Block. * * @param WaitList * Pointer to the Wait List associated to the wait. * @return None. * * @remarks None. * *--*/ VOID NTAPI CsrDereferenceWait(IN PLIST_ENTRY WaitList) { PLIST_ENTRY NextEntry; PCSR_WAIT_BLOCK WaitBlock; /* Acquire the Process and Wait Locks */ CsrAcquireProcessLock(); CsrAcquireWaitLock(); /* Set the list pointers */ NextEntry = WaitList->Flink; /* Start the loop */ while (NextEntry != WaitList) { /* Get the wait block */ WaitBlock = CONTAINING_RECORD(NextEntry, CSR_WAIT_BLOCK, WaitList); /* Move to the next entry */ NextEntry = NextEntry->Flink; /* Check if there's no Wait Routine */ if (!WaitBlock->WaitFunction) { /* Remove it from the Wait List */ if (WaitBlock->WaitList.Flink) { RemoveEntryList(&WaitBlock->WaitList); } /* Remove it from the User Wait List */ if (WaitBlock->UserWaitList.Flink) { RemoveEntryList(&WaitBlock->UserWaitList); } /* Dereference the thread waiting on it */ CsrDereferenceThread(WaitBlock->WaitThread); /* Free the block */ RtlFreeHeap(CsrHeap, 0, WaitBlock); } } /* Release the locks */ CsrReleaseWaitLock(); CsrReleaseProcessLock(); }
/*++ * @name CsrDereferenceProcess * @implemented NT4 * * The CsrDereferenceProcess routine removes a reference from a CSR Process. * * @param CsrThread * Pointer to the CSR Process to dereference. * * @return None. * * @remarks If the reference count has reached zero (ie: the CSR Process has * no more active references), it will be deleted. * *--*/ VOID NTAPI CsrDereferenceProcess(IN PCSR_PROCESS CsrProcess) { LONG LockCount; /* Acquire process lock */ CsrAcquireProcessLock(); /* Decrease reference count */ LockCount = --CsrProcess->ReferenceCount; ASSERT(LockCount >= 0); if (LockCount == 0) { /* Call the generic cleanup code */ CsrProcessRefcountZero(CsrProcess); } else { /* Just release the lock */ CsrReleaseProcessLock(); } }
/*++ * @name CsrSbCreateSession * * The CsrSbCreateSession API is called by the Session Manager whenever a new * session is created. * * @param ApiMessage * Pointer to the Session Manager API Message. * * @return TRUE in case of success, FALSE otherwise. * * @remarks The CsrSbCreateSession routine will initialize a new CSR NT * Session and allocate a new CSR Process for the subsystem process. * *--*/ BOOLEAN NTAPI CsrSbCreateSession(IN PSB_API_MSG ApiMessage) { PSB_CREATE_SESSION_MSG CreateSession = &ApiMessage->CreateSession; HANDLE hProcess, hThread; PCSR_PROCESS CsrProcess; NTSTATUS Status; KERNEL_USER_TIMES KernelTimes; PCSR_THREAD CsrThread; //PVOID ProcessData; //ULONG i; /* Save the Process and Thread Handles */ hProcess = CreateSession->ProcessInfo.ProcessHandle; hThread = CreateSession->ProcessInfo.ThreadHandle; /* Lock the Processes */ CsrAcquireProcessLock(); /* Allocate a new process */ CsrProcess = CsrAllocateProcess(); if (!CsrProcess) { /* Fail */ ApiMessage->ReturnValue = STATUS_NO_MEMORY; CsrReleaseProcessLock(); return TRUE; } /* Set the exception port */ Status = NtSetInformationProcess(hProcess, ProcessExceptionPort, &CsrApiPort, sizeof(HANDLE)); /* Check for success */ if (!NT_SUCCESS(Status)) { /* Fail the request */ CsrDeallocateProcess(CsrProcess); CsrReleaseProcessLock(); /* Strange as it seems, NTSTATUSes are actually returned */ return (BOOLEAN)STATUS_NO_MEMORY; } /* Get the Create Time */ Status = NtQueryInformationThread(hThread, ThreadTimes, &KernelTimes, sizeof(KERNEL_USER_TIMES), NULL); /* Check for success */ if (!NT_SUCCESS(Status)) { /* Fail the request */ CsrDeallocateProcess(CsrProcess); CsrReleaseProcessLock(); /* Strange as it seems, NTSTATUSes are actually returned */ return (BOOLEAN)Status; } /* Allocate a new Thread */ CsrThread = CsrAllocateThread(CsrProcess); if (!CsrThread) { /* Fail the request */ CsrDeallocateProcess(CsrProcess); CsrReleaseProcessLock(); ApiMessage->ReturnValue = STATUS_NO_MEMORY; return TRUE; } /* Setup the Thread Object */ CsrThread->CreateTime = KernelTimes.CreateTime; CsrThread->ClientId = CreateSession->ProcessInfo.ClientId; CsrThread->ThreadHandle = hThread; ProtectHandle(hThread); CsrThread->Flags = 0; /* Insert it into the Process List */ CsrInsertThread(CsrProcess, CsrThread); /* Setup Process Data */ CsrProcess->ClientId = CreateSession->ProcessInfo.ClientId; CsrProcess->ProcessHandle = hProcess; CsrProcess->NtSession = CsrAllocateNtSession(CreateSession->SessionId); /* Set the Process Priority */ CsrSetBackgroundPriority(CsrProcess); #if 0 /* Get the first data location */ ProcessData = &CsrProcess->ServerData[CSR_SERVER_DLL_MAX]; /* Loop every DLL */ for (i = 0; i < CSR_SERVER_DLL_MAX; i++) { /* Check if the DLL is loaded and has Process Data */ if (CsrLoadedServerDll[i] && CsrLoadedServerDll[i]->SizeOfProcessData) { /* Write the pointer to the data */ CsrProcess->ServerData[i] = ProcessData; /* Move to the next data location */ ProcessData = (PVOID)((ULONG_PTR)ProcessData + CsrLoadedServerDll[i]->SizeOfProcessData); } else { /* Nothing for this Process */ CsrProcess->ServerData[i] = NULL; } } #else /* HACKZ: should go in BaseSrv part of CreateCallback done in Insert below */ RtlInitializeCriticalSection(&CsrProcess->HandleTableLock); #endif /* Insert the Process */ CsrInsertProcess(NULL, NULL, CsrProcess); /* Activate the Thread */ ApiMessage->ReturnValue = NtResumeThread(hThread, NULL); /* Release lock and return */ CsrReleaseProcessLock(); return TRUE; }
/*++ * @name CsrDestroyProcess * @implemented NT4 * * The CsrDestroyProcess routine destroys the CSR Process corresponding to * a given Client ID. * * @param Cid * Pointer to the Client ID Structure corresponding to the CSR * Process which is about to be destroyed. * * @param ExitStatus * Unused. * * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING * if the CSR Process is already terminating. * * @remarks None. * *--*/ NTSTATUS NTAPI CsrDestroyProcess(IN PCLIENT_ID Cid, IN NTSTATUS ExitStatus) { PCSR_THREAD CsrThread; PCSR_PROCESS CsrProcess; CLIENT_ID ClientId = *Cid; PLIST_ENTRY NextEntry; /* Acquire lock */ CsrAcquireProcessLock(); /* Find the thread */ CsrThread = CsrLocateThreadByClientId(&CsrProcess, &ClientId); /* Make sure we got one back, and that it's not already gone */ if (!(CsrThread) || (CsrProcess->Flags & CsrProcessTerminating)) { /* Release the lock and return failure */ CsrReleaseProcessLock(); return STATUS_THREAD_IS_TERMINATING; } /* Set the terminated flag */ CsrProcess->Flags |= CsrProcessTerminating; /* Get the List Pointers */ NextEntry = CsrProcess->ThreadList.Flink; while (NextEntry != &CsrProcess->ThreadList) { /* Get the current thread entry */ CsrThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link); /* Move to the next entry */ NextEntry = NextEntry->Flink; /* Make sure the thread isn't already dead */ if (CsrThread->Flags & CsrThreadTerminated) { /* Go the the next thread */ continue; } /* Set the Terminated flag */ CsrThread->Flags |= CsrThreadTerminated; /* Acquire the Wait Lock */ CsrAcquireWaitLock(); /* Do we have an active wait block? */ if (CsrThread->WaitBlock) { /* Notify waiters of termination */ CsrNotifyWaitBlock(CsrThread->WaitBlock, NULL, NULL, NULL, CsrProcessTerminating, TRUE); } /* Release the Wait Lock */ CsrReleaseWaitLock(); /* Dereference the thread */ CsrLockedDereferenceThread(CsrThread); } /* Release the Process Lock and return success */ CsrReleaseProcessLock(); return STATUS_SUCCESS; }
/*++ * @name CsrCreateProcess * @implemented NT4 * * The CsrCreateProcess routine creates a CSR Process object for an NT Process. * * @param hProcess * Handle to an existing NT Process to which to associate this * CSR Process. * * @param hThread * Handle to an existing NT Thread to which to create its * corresponding CSR Thread for this CSR Process. * * @param ClientId * Pointer to the Client ID structure of the NT Process to associate * with this CSR Process. * * @param NtSession * @param Flags * @param DebugCid * * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise. * * @remarks None. * *--*/ NTSTATUS NTAPI CsrCreateProcess(IN HANDLE hProcess, IN HANDLE hThread, IN PCLIENT_ID ClientId, IN PCSR_NT_SESSION NtSession, IN ULONG Flags, IN PCLIENT_ID DebugCid) { PCSR_THREAD CurrentThread = CsrGetClientThread(); CLIENT_ID CurrentCid; PCSR_PROCESS CurrentProcess; PCSR_SERVER_DLL ServerDll; PVOID ProcessData; ULONG i; PCSR_PROCESS CsrProcess; NTSTATUS Status; PCSR_THREAD CsrThread; KERNEL_USER_TIMES KernelTimes; /* Get the current CID and lock Processes */ CurrentCid = CurrentThread->ClientId; CsrAcquireProcessLock(); /* Get the current CSR Thread */ CurrentThread = CsrLocateThreadByClientId(&CurrentProcess, &CurrentCid); if (!CurrentThread) { /* We've failed to locate the thread */ CsrReleaseProcessLock(); return STATUS_THREAD_IS_TERMINATING; } /* Allocate a new Process Object */ CsrProcess = CsrAllocateProcess(); if (!CsrProcess) { /* Couldn't allocate Process */ CsrReleaseProcessLock(); return STATUS_NO_MEMORY; } /* Inherit the Process Data */ CurrentProcess = CurrentThread->Process; ProcessData = &CsrProcess->ServerData[CSR_SERVER_DLL_MAX]; for (i = 0; i < CSR_SERVER_DLL_MAX; i++) { /* Get the current Server */ ServerDll = CsrLoadedServerDll[i]; /* Check if the DLL is Loaded and has Per Process Data */ if (ServerDll && ServerDll->SizeOfProcessData) { /* Set the pointer */ CsrProcess->ServerData[i] = ProcessData; /* Copy the Data */ RtlMoveMemory(ProcessData, CurrentProcess->ServerData[i], ServerDll->SizeOfProcessData); /* Update next data pointer */ ProcessData = (PVOID)((ULONG_PTR)ProcessData + ServerDll->SizeOfProcessData); } else { /* No data for this Server */ CsrProcess->ServerData[i] = NULL; } } /* Set the Exception Port for us */ Status = NtSetInformationProcess(hProcess, ProcessExceptionPort, &CsrApiPort, sizeof(CsrApiPort)); if (!NT_SUCCESS(Status)) { /* Failed */ CsrDeallocateProcess(CsrProcess); CsrReleaseProcessLock(); return STATUS_NO_MEMORY; } /* Check if CreateProcess got CREATE_NEW_PROCESS_GROUP */ if (Flags & CsrProcessCreateNewGroup) { /* * We create the process group leader of a new process group, therefore * its process group ID and sequence number are its own ones. */ CsrProcess->ProcessGroupId = HandleToUlong(ClientId->UniqueProcess); CsrProcess->ProcessGroupSequence = CsrProcess->SequenceNumber; } else { /* Inherit the process group ID and sequence number from the current process */ CsrProcess->ProcessGroupId = CurrentProcess->ProcessGroupId; CsrProcess->ProcessGroupSequence = CurrentProcess->ProcessGroupSequence; } /* Check if this is a console process */ if (Flags & CsrProcessIsConsoleApp) CsrProcess->Flags |= CsrProcessIsConsoleApp; /* Mask out non-debug flags */ Flags &= ~(CsrProcessIsConsoleApp | CsrProcessCreateNewGroup | CsrProcessPriorityFlags); /* Check if every process will be debugged */ if (!(Flags) && (CurrentProcess->DebugFlags & CsrDebugProcessChildren)) { /* Pass it on to the current process */ CsrProcess->DebugFlags = CsrDebugProcessChildren; CsrProcess->DebugCid = CurrentProcess->DebugCid; } /* Check if Debugging was used on this process */ if ((Flags & (CsrDebugOnlyThisProcess | CsrDebugProcessChildren)) && (DebugCid)) { /* Save the debug flag used */ CsrProcess->DebugFlags = Flags; /* Save the CID */ CsrProcess->DebugCid = *DebugCid; } /* Check if Debugging is enabled */ if (CsrProcess->DebugFlags) { /* Set the Debug Port for us */ Status = NtSetInformationProcess(hProcess, ProcessDebugPort, &CsrApiPort, sizeof(CsrApiPort)); ASSERT(NT_SUCCESS(Status)); if (!NT_SUCCESS(Status)) { /* Failed */ CsrDeallocateProcess(CsrProcess); CsrReleaseProcessLock(); return STATUS_NO_MEMORY; } } /* Get the Thread Create Time */ Status = NtQueryInformationThread(hThread, ThreadTimes, &KernelTimes, sizeof(KernelTimes), NULL); if (!NT_SUCCESS(Status)) { /* Failed */ CsrDeallocateProcess(CsrProcess); CsrReleaseProcessLock(); return STATUS_NO_MEMORY; } /* Allocate a CSR Thread Structure */ CsrThread = CsrAllocateThread(CsrProcess); if (!CsrThread) { /* Failed */ CsrDeallocateProcess(CsrProcess); CsrReleaseProcessLock(); return STATUS_NO_MEMORY; } /* Save the data we have */ CsrThread->CreateTime = KernelTimes.CreateTime; CsrThread->ClientId = *ClientId; CsrThread->ThreadHandle = hThread; ProtectHandle(hThread); CsrThread->Flags = 0; /* Insert the Thread into the Process */ Status = CsrInsertThread(CsrProcess, CsrThread); if (!NT_SUCCESS(Status)) { /* Bail out */ CsrDeallocateProcess(CsrProcess); CsrDeallocateThread(CsrThread); CsrReleaseProcessLock(); return Status; } /* Reference the session */ CsrReferenceNtSession(NtSession); CsrProcess->NtSession = NtSession; /* Setup Process Data */ CsrProcess->ClientId = *ClientId; CsrProcess->ProcessHandle = hProcess; CsrProcess->ShutdownLevel = 0x280; /* Set the Priority to Background */ CsrSetBackgroundPriority(CsrProcess); /* Insert the Process */ CsrInsertProcess(CurrentProcess, CsrProcess); /* Release lock and return */ CsrReleaseProcessLock(); return Status; }
/*++ * @name CsrShutdownProcesses * @implemented NT4 * * The CsrShutdownProcesses routine shuts down every CSR Process possible * and calls each Server DLL's shutdown notification. * * @param CallerLuid * Pointer to the LUID of the CSR Process that is ordering the * shutdown. * * @param Flags * Flags to send to the shutdown notification routine. * * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise. * * @remarks None. * *--*/ NTSTATUS NTAPI CsrShutdownProcesses(IN PLUID CallerLuid, IN ULONG Flags) { PLIST_ENTRY NextEntry; PCSR_PROCESS CsrProcess; NTSTATUS Status; BOOLEAN FirstTry; ULONG i; PCSR_SERVER_DLL ServerDll; ULONG Result = 0; /* Acquire process lock */ CsrAcquireProcessLock(); /* Add shutdown flag */ CsrRootProcess->ShutdownFlags |= CsrShutdownSystem; /* Get the list pointers */ NextEntry = CsrRootProcess->ListLink.Flink; while (NextEntry != &CsrRootProcess->ListLink) { /* Get the Process */ CsrProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink); /* Move to the next entry */ NextEntry = NextEntry->Flink; /* Remove the skip flag, set shutdown flags to 0 */ CsrProcess->Flags &= ~CsrProcessSkipShutdown; CsrProcess->ShutdownFlags = 0; } /* Set shutdown Priority */ CsrSetToShutdownPriority(); /* Start looping */ while (TRUE) { /* Find the next process to shutdown */ CsrProcess = FindProcessForShutdown(CallerLuid); if (!CsrProcess) break; /* Increase reference to process */ CsrLockedReferenceProcess(CsrProcess); FirstTry = TRUE; while (TRUE) { /* Loop all the servers */ for (i = 0; i < CSR_SERVER_DLL_MAX; i++) { /* Get the current server */ ServerDll = CsrLoadedServerDll[i]; /* Check if it's valid and if it has a Shutdown Process Callback */ if (ServerDll && ServerDll->ShutdownProcessCallback) { /* Release the lock, make the callback, and acquire it back */ CsrReleaseProcessLock(); Result = ServerDll->ShutdownProcessCallback(CsrProcess, Flags, FirstTry); CsrAcquireProcessLock(); /* Check the result */ if (Result == CsrShutdownCsrProcess) { /* The callback unlocked the process */ break; } else if (Result == CsrShutdownCancelled) { /* Check if this was a forced shutdown */ if (Flags & EWX_FORCE) { DPRINT1("Process %x cancelled forced shutdown (Dll = %d)\n", CsrProcess->ClientId.UniqueProcess, i); DbgBreakPoint(); } /* Shutdown was cancelled, unlock and exit */ CsrReleaseProcessLock(); Status = STATUS_CANCELLED; goto Quickie; } } } /* No matches during the first try, so loop again */ if (FirstTry && (Result == CsrShutdownNonCsrProcess)) { FirstTry = FALSE; continue; } /* Second try, break out */ break; } /* We've reached the final loop here, so dereference */ if (i == CSR_SERVER_DLL_MAX) CsrLockedDereferenceProcess(CsrProcess); } /* Success path */ CsrReleaseProcessLock(); Status = STATUS_SUCCESS; Quickie: /* Return to normal priority */ CsrSetToNormalPriority(); return Status; }
/*++ * @name CsrApiRequestThread * * The CsrApiRequestThread routine handles incoming messages or connection * requests on the CSR API LPC Port. * * @param Parameter * System-default user-defined parameter. Unused. * * @return The thread exit code, if the thread is terminated. * * @remarks Before listening on the port, the routine will first attempt * to connect to the user subsystem. * *--*/ NTSTATUS NTAPI CsrApiRequestThread(IN PVOID Parameter) { PTEB Teb = NtCurrentTeb(); LARGE_INTEGER TimeOut; PCSR_THREAD CurrentThread, CsrThread; NTSTATUS Status; CSR_REPLY_CODE ReplyCode; PCSR_API_MESSAGE ReplyMsg; CSR_API_MESSAGE ReceiveMsg; PCSR_PROCESS CsrProcess; PHARDERROR_MSG HardErrorMsg; PVOID PortContext; PCSR_SERVER_DLL ServerDll; PCLIENT_DIED_MSG ClientDiedMsg; PDBGKM_MSG DebugMessage; ULONG ServerId, ApiId, MessageType, i; HANDLE ReplyPort; /* Setup LPC loop port and message */ ReplyMsg = NULL; ReplyPort = CsrApiPort; /* Connect to user32 */ while (!CsrConnectToUser()) { /* Set up the timeout for the connect (30 seconds) */ TimeOut.QuadPart = -30 * 1000 * 1000 * 10; /* Keep trying until we get a response */ Teb->Win32ClientInfo[0] = 0; NtDelayExecution(FALSE, &TimeOut); } /* Get our thread */ CurrentThread = Teb->CsrClientThread; /* If we got an event... */ if (Parameter) { /* Set it, to let stuff waiting on us load */ Status = NtSetEvent((HANDLE)Parameter, NULL); ASSERT(NT_SUCCESS(Status)); /* Increase the Thread Counts */ InterlockedIncrementUL(&CsrpStaticThreadCount); InterlockedIncrementUL(&CsrpDynamicThreadTotal); } /* Now start the loop */ while (TRUE) { /* Make sure the real CID is set */ Teb->RealClientId = Teb->ClientId; /* Debug check */ if (Teb->CountOfOwnedCriticalSections) { DPRINT1("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n", Teb->CountOfOwnedCriticalSections); DPRINT1("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n", &ReceiveMsg, ReplyMsg); DbgBreakPoint(); } /* Wait for a message to come through */ Status = NtReplyWaitReceivePort(ReplyPort, &PortContext, &ReplyMsg->Header, &ReceiveMsg.Header); /* Check if we didn't get success */ if (Status != STATUS_SUCCESS) { /* Was it a failure or another success code? */ if (!NT_SUCCESS(Status)) { /* Check for specific status cases */ if ((Status != STATUS_INVALID_CID) && (Status != STATUS_UNSUCCESSFUL) && ((Status == STATUS_INVALID_HANDLE) || (ReplyPort == CsrApiPort))) { /* Notify the debugger */ DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status); DPRINT1("CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPort, CsrApiPort); } /* We failed big time, so start out fresh */ ReplyMsg = NULL; ReplyPort = CsrApiPort; continue; } else { /* A strange "success" code, just try again */ DPRINT1("NtReplyWaitReceivePort returned \"success\" status 0x%x\n", Status); continue; } } /* Use whatever Client ID we got */ Teb->RealClientId = ReceiveMsg.Header.ClientId; /* Get the Message Type */ MessageType = ReceiveMsg.Header.u2.s2.Type; /* Handle connection requests */ if (MessageType == LPC_CONNECTION_REQUEST) { /* Handle the Connection Request */ CsrApiHandleConnectionRequest(&ReceiveMsg); ReplyMsg = NULL; ReplyPort = CsrApiPort; continue; } /* It's some other kind of request. Get the lock for the lookup */ CsrAcquireProcessLock(); /* Now do the lookup to get the CSR_THREAD */ CsrThread = CsrLocateThreadByClientId(&CsrProcess, &ReceiveMsg.Header.ClientId); /* Did we find a thread? */ if (!CsrThread) { /* This wasn't a CSR Thread, release lock */ CsrReleaseProcessLock(); /* If this was an exception, handle it */ if (MessageType == LPC_EXCEPTION) { ReplyMsg = &ReceiveMsg; ReplyPort = CsrApiPort; ReplyMsg->Status = DBG_CONTINUE; } else if (MessageType == LPC_PORT_CLOSED || MessageType == LPC_CLIENT_DIED) { /* The Client or Port are gone, loop again */ ReplyMsg = NULL; ReplyPort = CsrApiPort; } else if (MessageType == LPC_ERROR_EVENT) { /* If it's a hard error, handle this too */ HardErrorMsg = (PHARDERROR_MSG)&ReceiveMsg; /* Default it to unhandled */ HardErrorMsg->Response = ResponseNotHandled; /* Check if there are free api threads */ CsrpCheckRequestThreads(); if (CsrpStaticThreadCount) { /* Loop every Server DLL */ for (i = 0; i < CSR_SERVER_DLL_MAX; i++) { /* Get the Server DLL */ ServerDll = CsrLoadedServerDll[i]; /* Check if it's valid and if it has a Hard Error Callback */ if ((ServerDll) && (ServerDll->HardErrorCallback)) { /* Call it */ ServerDll->HardErrorCallback(NULL /* == CsrThread */, HardErrorMsg); /* If it's handled, get out of here */ if (HardErrorMsg->Response != ResponseNotHandled) break; } } } /* Increase the thread count */ InterlockedIncrementUL(&CsrpStaticThreadCount); /* If the response was 0xFFFFFFFF, we'll ignore it */ if (HardErrorMsg->Response == 0xFFFFFFFF) { ReplyMsg = NULL; ReplyPort = CsrApiPort; } else { ReplyMsg = &ReceiveMsg; ReplyPort = CsrApiPort; } } else if (MessageType == LPC_REQUEST) { /* This is an API Message coming from a non-CSR Thread */ ReplyMsg = &ReceiveMsg; ReplyPort = CsrApiPort; ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION; } else if (MessageType == LPC_DATAGRAM) { /* This is an API call, get the Server ID */ ServerId = CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg.ApiNumber); /* Make sure that the ID is within limits, and the Server DLL loaded */ ServerDll = NULL; if ((ServerId >= CSR_SERVER_DLL_MAX) || (!(ServerDll = CsrLoadedServerDll[ServerId]))) { /* We are beyond the Maximum Server ID */ DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n", ServerId, ServerDll); // DbgBreakPoint(); ReplyMsg = NULL; ReplyPort = CsrApiPort; continue; } /* Get the API ID, normalized with our Base ID */ ApiId = CSR_API_NUMBER_TO_API_ID(ReceiveMsg.ApiNumber) - ServerDll->ApiBase; /* Make sure that the ID is within limits, and the entry exists */ if (ApiId >= ServerDll->HighestApiSupported) { /* We are beyond the Maximum API ID, or it doesn't exist */ DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n", CSR_API_NUMBER_TO_API_ID(ReceiveMsg.ApiNumber), &ServerDll->Name); ReplyPort = CsrApiPort; ReplyMsg = NULL; continue; } #ifdef CSR_DBG if (CsrDebug & 2) { DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n", Teb->ClientId.UniqueThread, ReceiveMsg.Header.ClientId.UniqueProcess, ReceiveMsg.Header.ClientId.UniqueThread, ServerDll->NameTable[ApiId], NULL); } #endif /* Assume success */ ReceiveMsg.Status = STATUS_SUCCESS; /* Validation complete, start SEH */ _SEH2_TRY { /* Make sure we have enough threads */ CsrpCheckRequestThreads(); /* Call the API and get the reply code */ ReplyMsg = NULL; ReplyPort = CsrApiPort; ServerDll->DispatchTable[ApiId](&ReceiveMsg, &ReplyCode); /* Increase the static thread count */ InterlockedIncrementUL(&CsrpStaticThreadCount); } _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation())) { ReplyMsg = NULL; ReplyPort = CsrApiPort; } _SEH2_END; } else {
/*++ * @name CsrApiHandleConnectionRequest * * The CsrApiHandleConnectionRequest routine handles and accepts a new * connection request to the CSR API LPC Port. * * @param ApiMessage * Pointer to the incoming CSR API Message which contains the * connection request. * * @return STATUS_SUCCESS in case of success, or status code which caused * the routine to error. * * @remarks This routine is responsible for attaching the Shared Section to * new clients connecting to CSR. * *--*/ NTSTATUS NTAPI CsrApiHandleConnectionRequest(IN PCSR_API_MESSAGE ApiMessage) { PCSR_THREAD CsrThread = NULL; PCSR_PROCESS CsrProcess = NULL; NTSTATUS Status = STATUS_SUCCESS; PCSR_API_CONNECTINFO ConnectInfo = &ApiMessage->ConnectionInfo; BOOLEAN AllowConnection = FALSE; REMOTE_PORT_VIEW RemotePortView; HANDLE ServerPort; /* Acquire the Process Lock */ CsrAcquireProcessLock(); /* Lookup the CSR Thread */ CsrThread = CsrLocateThreadByClientId(NULL, &ApiMessage->Header.ClientId); /* Check if we have a thread */ if (CsrThread) { /* Get the Process */ CsrProcess = CsrThread->Process; /* Make sure we have a Process as well */ if (CsrProcess) { /* Reference the Process */ CsrLockedReferenceProcess(CsrProcess); /* Release the lock */ CsrReleaseProcessLock(); /* Duplicate the Object Directory */ Status = NtDuplicateObject(NtCurrentProcess(), CsrObjectDirectory, CsrProcess->ProcessHandle, &ConnectInfo->ObjectDirectory, 0, 0, DUPLICATE_SAME_ACCESS | DUPLICATE_SAME_ATTRIBUTES); /* Acquire the lock */ CsrAcquireProcessLock(); /* Check for success */ if (NT_SUCCESS(Status)) { /* Attach the Shared Section */ Status = CsrSrvAttachSharedSection(CsrProcess, ConnectInfo); /* Check how this went */ if (NT_SUCCESS(Status)) { /* Allow the connection, and return debugging flag */ ConnectInfo->DebugFlags = CsrDebug; AllowConnection = TRUE; } } /* Dereference the project */ CsrLockedDereferenceProcess(CsrProcess); } } /* Release the lock */ CsrReleaseProcessLock(); /* Setup the Port View Structure */ RemotePortView.Length = sizeof(REMOTE_PORT_VIEW); RemotePortView.ViewSize = 0; RemotePortView.ViewBase = NULL; /* Save the Process ID */ ConnectInfo->ServerProcessId = NtCurrentTeb()->ClientId.UniqueProcess; /* Accept the Connection */ Status = NtAcceptConnectPort(&ServerPort, AllowConnection ? UlongToPtr(CsrProcess->SequenceNumber) : 0, &ApiMessage->Header, AllowConnection, NULL, &RemotePortView); if (!NT_SUCCESS(Status)) { DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status); } else if (AllowConnection) { if (CsrDebug & 2) { DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n", ApiMessage->Header.ClientId.UniqueProcess, ApiMessage->Header.ClientId.UniqueThread, RemotePortView.ViewBase, RemotePortView.ViewSize); } /* Set some Port Data in the Process */ CsrProcess->ClientPort = ServerPort; CsrProcess->ClientViewBase = (ULONG_PTR)RemotePortView.ViewBase; CsrProcess->ClientViewBounds = (ULONG_PTR)((ULONG_PTR)RemotePortView.ViewBase + (ULONG_PTR)RemotePortView.ViewSize); /* Complete the connection */ Status = NtCompleteConnectPort(ServerPort); if (!NT_SUCCESS(Status)) { DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status); } } else { DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n", ApiMessage->Header.ClientId.UniqueProcess, ApiMessage->Header.ClientId.UniqueThread); } /* Return status to caller */ return Status; }