VOID LpcpClosePort( IN PEPROCESS Process OPTIONAL, IN PVOID Object, IN ACCESS_MASK GrantedAccess, IN ULONG ProcessHandleCount, IN ULONG SystemHandleCount ) { PLPCP_PORT_OBJECT Port = Object; if ( (Port->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT ) { if ( SystemHandleCount == 0 ) { LpcpDestroyPortQueue( Port, TRUE ); } else if ( SystemHandleCount == 1 ) { LpcpDestroyPortQueue( Port, FALSE ); } } return; }
VOID NTAPI LpcpClosePort(IN PEPROCESS Process OPTIONAL, IN PVOID Object, IN ACCESS_MASK GrantedAccess, IN ULONG ProcessHandleCount, IN ULONG SystemHandleCount) { PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)Object; LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags); /* Only Server-side Connection Ports need clean up*/ if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT) { /* Check the handle count */ switch (SystemHandleCount) { /* No handles left */ case 0: /* Destroy the port queue */ LpcpDestroyPortQueue(Port, TRUE); break; /* Last handle remaining */ case 1: /* Reset the queue only */ LpcpDestroyPortQueue(Port, FALSE); /* More handles remain, do nothing */ default: break; } } }
VOID LpcpClosePort ( IN PEPROCESS Process OPTIONAL, IN PVOID Object, IN ACCESS_MASK GrantedAccess, IN ULONG_PTR ProcessHandleCount, IN ULONG_PTR SystemHandleCount ) /*++ Routine Description: This routine is the callback used for closing a port object. Arguments: Process - Supplies an optional pointer to the process whose port is being closed Object - Supplies a pointer to the port object being closed GrantedAccess - Supplies the access granted to the handle closing port object ProcessHandleCount - Supplies the number of process handles remaining to the object SystemHandleCount - Supplies the number of system handles remaining to the object Return Value: None. --*/ { // // Translate the object to what it really is, an LPCP port object // PLPCP_PORT_OBJECT Port = Object; UNREFERENCED_PARAMETER (Process); UNREFERENCED_PARAMETER (GrantedAccess); UNREFERENCED_PARAMETER (ProcessHandleCount); // // We only have work to do if the object is a server communication port // if ( (Port->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT ) { // // If this is a server communication port without any system handles // then we can completely destroy the communication queue for the // port // if ( SystemHandleCount == 0 ) { LpcpDestroyPortQueue( Port, TRUE ); // // If there is only one system handle left then we'll reset the // communication queue for the port // } else if ( SystemHandleCount == 1 ) { LpcpDestroyPortQueue( Port, FALSE ); } // // Otherwise we do nothing // } return; }
VOID LpcpDeletePort ( IN PVOID Object ) /*++ Routine Description: This routine is the callback used for deleting a port object. Arguments: Object - Supplies a pointer to the port object being deleted Return Value: None. --*/ { PETHREAD CurrentThread; PLPCP_PORT_OBJECT Port = Object; PLPCP_PORT_OBJECT ConnectionPort; LPC_CLIENT_DIED_MSG ClientPortClosedDatagram; PLPCP_MESSAGE Msg; PLIST_ENTRY Head, Next; HANDLE CurrentProcessId; NTSTATUS Status; LARGE_INTEGER RetryInterval = {(ULONG)(-10 * 1000 * 100), -1}; // 100 milliseconds PAGED_CODE(); CurrentThread = PsGetCurrentThread (); // // If the port is a server communication port then make sure that if // there is a dangling client thread that we get rid of it. This // handles the case of someone calling NtAcceptConnectPort and not // calling NtCompleteConnectPort // if ((Port->Flags & PORT_TYPE) == SERVER_COMMUNICATION_PORT) { PETHREAD ClientThread; LpcpAcquireLpcpLockByThread(CurrentThread); if ((ClientThread = Port->ClientThread) != NULL) { Port->ClientThread = NULL; LpcpReleaseLpcpLock(); ObDereferenceObject( ClientThread ); } else { LpcpReleaseLpcpLock(); } } // // Send an LPC_PORT_CLOSED datagram to whoever is connected // to this port so they know they are no longer connected. // if ((Port->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) { ClientPortClosedDatagram.PortMsg.u1.s1.TotalLength = sizeof( ClientPortClosedDatagram ); ClientPortClosedDatagram.PortMsg.u1.s1.DataLength = sizeof( ClientPortClosedDatagram.CreateTime ); ClientPortClosedDatagram.PortMsg.u2.s2.Type = LPC_PORT_CLOSED; ClientPortClosedDatagram.PortMsg.u2.s2.DataInfoOffset = 0; ClientPortClosedDatagram.CreateTime = PsGetCurrentProcess()->CreateTime; Status = LpcRequestPort( Port, (PPORT_MESSAGE)&ClientPortClosedDatagram ); while (Status == STATUS_NO_MEMORY) { KeDelayExecutionThread(KernelMode, FALSE, &RetryInterval); Status = LpcRequestPort( Port, (PPORT_MESSAGE)&ClientPortClosedDatagram ); } } // // If connected, disconnect the port, and then scan the message queue // for this port and dereference any messages in the queue. // LpcpDestroyPortQueue( Port, TRUE ); // // If we had mapped sections into the server or client communication ports, // we need to unmap them in the context of that process. // if ( (Port->ClientSectionBase != NULL) || (Port->ServerSectionBase != NULL) ) { // // If the client has a port memory view, then unmap it // if (Port->ClientSectionBase != NULL) { MmUnmapViewOfSection( Port->MappingProcess, Port->ClientSectionBase ); } // // If the server has a port memory view, then unmap it // if (Port->ServerSectionBase != NULL) { MmUnmapViewOfSection( Port->MappingProcess, Port->ServerSectionBase ); } // // Removing the reference added while mapping the section // ObDereferenceObject( Port->MappingProcess ); Port->MappingProcess = NULL; } // // Dereference the pointer to the connection port if it is not // this port. // LpcpAcquireLpcpLockByThread(CurrentThread); ConnectionPort = Port->ConnectionPort; if (ConnectionPort) { CurrentProcessId = CurrentThread->Cid.UniqueProcess; Head = &ConnectionPort->LpcDataInfoChainHead; Next = Head->Flink; while (Next != Head) { Msg = CONTAINING_RECORD( Next, LPCP_MESSAGE, Entry ); Next = Next->Flink; if (Port == ConnectionPort) { // // If the Connection port is going away free all queued messages // RemoveEntryList( &Msg->Entry ); InitializeListHead( &Msg->Entry ); LpcpFreeToPortZone( Msg, LPCP_MUTEX_OWNED ); // // In LpcpFreeToPortZone the LPC lock is released and reacquired. // Another thread might free the LPC message captured above // in Next. We need to restart the search at the list head. // Next = Head->Flink; } else if ((Msg->Request.ClientId.UniqueProcess == CurrentProcessId) && ((Msg->SenderPort == Port) || (Msg->SenderPort == Port->ConnectedPort) || (Msg->SenderPort == ConnectionPort))) { // // Test whether the message come from the same port and process // LpcpTrace(( "%s Freeing DataInfo Message %lx (%u.%u) Port: %lx\n", PsGetCurrentProcess()->ImageFileName, Msg, Msg->Request.MessageId, Msg->Request.CallbackId, ConnectionPort )); RemoveEntryList( &Msg->Entry ); InitializeListHead( &Msg->Entry ); LpcpFreeToPortZone( Msg, LPCP_MUTEX_OWNED ); // // In LpcpFreeToPortZone the LPC lock is released and reacquired. // Another thread might free the LPC message captured above // in Next. We need to restart the search at the list head. // Next = Head->Flink; } } LpcpReleaseLpcpLock(); if (ConnectionPort != Port) { ObDereferenceObject( ConnectionPort ); } } else { LpcpReleaseLpcpLock(); } if (((Port->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT) && (ConnectionPort->ServerProcess != NULL)) { ObDereferenceObject( ConnectionPort->ServerProcess ); ConnectionPort->ServerProcess = NULL; } // // Free any static client security context // LpcpFreePortClientSecurity( Port ); // // And return to our caller // return; }
VOID NTAPI LpcpDeletePort(IN PVOID ObjectBody) { LARGE_INTEGER Timeout; PETHREAD Thread; PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)ObjectBody; PLPCP_PORT_OBJECT ConnectionPort; PLPCP_MESSAGE Message; PLIST_ENTRY ListHead, NextEntry; HANDLE Pid; CLIENT_DIED_MSG ClientDiedMsg; PAGED_CODE(); LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags); Timeout.QuadPart = -1000000; /* Check if this is a communication port */ if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_COMMUNICATION_PORT) { /* Acquire the lock */ KeAcquireGuardedMutex(&LpcpLock); /* Get the thread */ Thread = Port->ClientThread; if (Thread) { /* Clear it */ Port->ClientThread = NULL; /* Release the lock and dereference */ KeReleaseGuardedMutex(&LpcpLock); ObDereferenceObject(Thread); } else { /* Release the lock */ KeReleaseGuardedMutex(&LpcpLock); } } /* Check if this is a client-side port */ if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT) { /* Setup the client died message */ ClientDiedMsg.h.u1.s1.TotalLength = sizeof(ClientDiedMsg); ClientDiedMsg.h.u1.s1.DataLength = sizeof(ClientDiedMsg.CreateTime); ClientDiedMsg.h.u2.ZeroInit = 0; ClientDiedMsg.h.u2.s2.Type = LPC_PORT_CLOSED; ClientDiedMsg.CreateTime = PsGetCurrentProcess()->CreateTime; /* Send it */ for (;;) { /* Send the message */ if (LpcRequestPort(Port, &ClientDiedMsg.h) != STATUS_NO_MEMORY) break; /* Wait until trying again */ KeDelayExecutionThread(KernelMode, FALSE, &Timeout); } } /* Destroy the port queue */ LpcpDestroyPortQueue(Port, TRUE); /* Check if we had views */ if ((Port->ClientSectionBase) || (Port->ServerSectionBase)) { /* Check if we had a client view */ if (Port->ClientSectionBase) { /* Unmap it */ MmUnmapViewOfSection(Port->MappingProcess, Port->ClientSectionBase); } /* Check for a server view */ if (Port->ServerSectionBase) { /* Unmap it */ MmUnmapViewOfSection(Port->MappingProcess, Port->ServerSectionBase); } /* Dereference the mapping process */ ObDereferenceObject(Port->MappingProcess); Port->MappingProcess = NULL; } /* Acquire the lock */ KeAcquireGuardedMutex(&LpcpLock); /* Get the connection port */ ConnectionPort = Port->ConnectionPort; if (ConnectionPort) { /* Get the PID */ Pid = PsGetCurrentProcessId(); /* Loop the data lists */ ListHead = &ConnectionPort->LpcDataInfoChainHead; NextEntry = ListHead->Flink; while (NextEntry != ListHead) { /* Get the message */ Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry); NextEntry = NextEntry->Flink; /* Check if this is the connection port */ if (Port == ConnectionPort) { /* Free queued messages */ RemoveEntryList(&Message->Entry); InitializeListHead(&Message->Entry); LpcpFreeToPortZone(Message, LPCP_LOCK_HELD); /* Restart at the head */ NextEntry = ListHead->Flink; } else if ((Message->Request.ClientId.UniqueProcess == Pid) && ((Message->SenderPort == Port) || (Message->SenderPort == Port->ConnectedPort) || (Message->SenderPort == ConnectionPort))) { /* Remove it */ RemoveEntryList(&Message->Entry); InitializeListHead(&Message->Entry); LpcpFreeToPortZone(Message, LPCP_LOCK_HELD); /* Restart at the head */ NextEntry = ListHead->Flink; } } /* Release the lock */ KeReleaseGuardedMutex(&LpcpLock); /* Dereference the object unless it's the same port */ if (ConnectionPort != Port) ObDereferenceObject(ConnectionPort); /* Check if this is a connection port with a server process */ if (((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT) && (ConnectionPort->ServerProcess)) { /* Dereference the server process */ ObDereferenceObject(ConnectionPort->ServerProcess); ConnectionPort->ServerProcess = NULL; } } else { /* Release the lock */ KeReleaseGuardedMutex(&LpcpLock); } /* Free client security */ LpcpFreePortClientSecurity(Port); LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p deleted\n", Port); }
VOID LpcpDeletePort( IN PVOID Object ) { PLPCP_PORT_OBJECT Port = Object; PLPCP_PORT_OBJECT ConnectionPort; LPC_CLIENT_DIED_MSG ClientPortClosedDatagram; PLPCP_MESSAGE Msg; PLIST_ENTRY Head, Next; HANDLE CurrentProcessId; PAGED_CODE(); // // Send an LPC_PORT_CLOSED datagram to whoever is connected // to this port so they know they are no longer connected. // if ((Port->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) { ClientPortClosedDatagram.PortMsg.u1.s1.TotalLength = sizeof( ClientPortClosedDatagram ); ClientPortClosedDatagram.PortMsg.u1.s1.DataLength = sizeof( ClientPortClosedDatagram.CreateTime ); ClientPortClosedDatagram.PortMsg.u2.s2.Type = LPC_PORT_CLOSED; ClientPortClosedDatagram.PortMsg.u2.s2.DataInfoOffset = 0; ClientPortClosedDatagram.CreateTime = PsGetCurrentProcess()->CreateTime; LpcRequestPort( Port, (PPORT_MESSAGE)&ClientPortClosedDatagram ); } // // If connected, disconnect the port, and then scan the message queue // for this port and dereference any messages in the queue. // LpcpDestroyPortQueue( Port, TRUE ); // // If the client has a port memory view, then unmap it // if (Port->ClientSectionBase != NULL) { ZwUnmapViewOfSection( NtCurrentProcess(), Port->ClientSectionBase ); } // // If the server has a port memory view, then unmap it // if (Port->ServerSectionBase != NULL) { ZwUnmapViewOfSection( NtCurrentProcess(), Port->ServerSectionBase ); } // // Dereference the pointer to the connection port if it is not // this port. // if (ConnectionPort = Port->ConnectionPort) { CurrentProcessId = PsGetCurrentThread()->Cid.UniqueProcess; ExAcquireFastMutex( &LpcpLock ); Head = &ConnectionPort->LpcDataInfoChainHead; Next = Head->Flink; while (Next != Head) { Msg = CONTAINING_RECORD( Next, LPCP_MESSAGE, Entry ); Next = Next->Flink; if (Msg->Request.ClientId.UniqueProcess == CurrentProcessId) { LpcpTrace(( "%s Freeing DataInfo Message %lx (%u.%u) Port: %lx\n", PsGetCurrentProcess()->ImageFileName, Msg, Msg->Request.MessageId, Msg->Request.CallbackId, ConnectionPort )); RemoveEntryList( &Msg->Entry ); LpcpFreeToPortZone( Msg, TRUE ); } } ExReleaseFastMutex( &LpcpLock ); if (ConnectionPort != Port) { ObDereferenceObject( ConnectionPort ); } } // // Free any static client security context // LpcpFreePortClientSecurity( Port ); }
VOID LpcpDeletePort ( IN PVOID Object ) /*++ Routine Description: This routine is the callback used for deleting a port object. Arguments: Object - Supplies a pointer to the port object being deleted Return Value: None. --*/ { PLPCP_PORT_OBJECT Port = Object; PLPCP_PORT_OBJECT ConnectionPort; LPC_CLIENT_DIED_MSG ClientPortClosedDatagram; PLPCP_MESSAGE Msg; PLIST_ENTRY Head, Next; HANDLE CurrentProcessId; PAGED_CODE(); // // If the port is a server communication port then make sure that if // there is a dangling client thread that we get rid of it. This // handles the case of someone calling NtAcceptConnectPort and not // calling NtCompleteConnectPort // LpcpPortExtraDataDestroy( Port ); if ((Port->Flags & PORT_TYPE) == SERVER_COMMUNICATION_PORT) { PETHREAD ClientThread; LpcpAcquireLpcpLock(); if ((ClientThread = Port->ClientThread) != NULL) { Port->ClientThread = NULL; LpcpReleaseLpcpLock(); ObDereferenceObject( ClientThread ); } else { LpcpReleaseLpcpLock(); } } // // Send an LPC_PORT_CLOSED datagram to whoever is connected // to this port so they know they are no longer connected. // if ((Port->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) { ClientPortClosedDatagram.PortMsg.u1.s1.TotalLength = sizeof( ClientPortClosedDatagram ); ClientPortClosedDatagram.PortMsg.u1.s1.DataLength = sizeof( ClientPortClosedDatagram.CreateTime ); ClientPortClosedDatagram.PortMsg.u2.s2.Type = LPC_PORT_CLOSED; ClientPortClosedDatagram.PortMsg.u2.s2.DataInfoOffset = 0; ClientPortClosedDatagram.CreateTime = PsGetCurrentProcess()->CreateTime; LpcRequestPort( Port, (PPORT_MESSAGE)&ClientPortClosedDatagram ); } // // If connected, disconnect the port, and then scan the message queue // for this port and dereference any messages in the queue. // LpcpDestroyPortQueue( Port, TRUE ); // // If the client has a port memory view, then unmap it // if (Port->ClientSectionBase != NULL) { MmUnmapViewOfSection( PsGetCurrentProcess(), Port->ClientSectionBase ); } // // If the server has a port memory view, then unmap it // if (Port->ServerSectionBase != NULL) { MmUnmapViewOfSection( PsGetCurrentProcess(), Port->ServerSectionBase ); } // // Dereference the pointer to the connection port if it is not // this port. // if (ConnectionPort = Port->ConnectionPort) { CurrentProcessId = PsGetCurrentThread()->Cid.UniqueProcess; LpcpAcquireLpcpLock(); Head = &ConnectionPort->LpcDataInfoChainHead; Next = Head->Flink; while (Next != Head) { Msg = CONTAINING_RECORD( Next, LPCP_MESSAGE, Entry ); Next = Next->Flink; if (Msg->Request.ClientId.UniqueProcess == CurrentProcessId) { LpcpTrace(( "%s Freeing DataInfo Message %lx (%u.%u) Port: %lx\n", PsGetCurrentProcess()->ImageFileName, Msg, Msg->Request.MessageId, Msg->Request.CallbackId, ConnectionPort )); RemoveEntryList( &Msg->Entry ); LpcpFreeToPortZone( Msg, TRUE ); } } LpcpReleaseLpcpLock(); if (ConnectionPort != Port) { ObDereferenceObject( ConnectionPort ); } } if (((Port->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT) && (ConnectionPort->ServerProcess != NULL)) { ObDereferenceObject( ConnectionPort->ServerProcess ); ConnectionPort->ServerProcess = NULL; } // // Free any static client security context // LpcpFreePortClientSecurity( Port ); // // And return to our caller // return; }