mirror of https://github.com/lianthony/NT4.0
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
752 lines
26 KiB
752 lines
26 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
lpccompl.c
|
|
|
|
Abstract:
|
|
|
|
Local Inter-Process Communication (LPC) connection system services.
|
|
|
|
Author:
|
|
|
|
Steve Wood (stevewo) 15-May-1989
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "lpcp.h"
|
|
|
|
PLPCP_MESSAGE
|
|
LpcpRemoveConMsg(
|
|
IN PETHREAD ClientThread,
|
|
IN ULONG CapturedMessageId
|
|
);
|
|
|
|
VOID
|
|
LpcpRestoreConMsg(
|
|
IN PETHREAD ClientThread,
|
|
IN PLPCP_MESSAGE Msg
|
|
);
|
|
|
|
VOID
|
|
LpcpPrepareToWakeClient(
|
|
IN PETHREAD ClientThread
|
|
);
|
|
|
|
PVOID
|
|
LpcpCheckSectionToMap(
|
|
IN PLPCP_CONNECTION_MESSAGE ConnectMsg
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE,NtAcceptConnectPort)
|
|
#pragma alloc_text(PAGE,NtCompleteConnectPort)
|
|
#pragma alloc_text(PAGE,LpcpPrepareToWakeClient)
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
NtAcceptConnectPort(
|
|
OUT PHANDLE PortHandle,
|
|
IN PVOID PortContext OPTIONAL,
|
|
IN PPORT_MESSAGE ConnectionRequest,
|
|
IN BOOLEAN AcceptConnection,
|
|
IN OUT PPORT_VIEW ServerView OPTIONAL,
|
|
OUT PREMOTE_PORT_VIEW ClientView OPTIONAL
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
A server process can accept or reject a client connection request
|
|
using the NtCompleteConnectPort service.
|
|
|
|
The ConnectionRequest parameter must specify a connection request
|
|
returned by a previous call to the NtListenPort service. This
|
|
service will either complete the connection if the AcceptConnection
|
|
parameter is TRUE, or reject the connection request if the
|
|
AcceptConnection parameter is FALSE.
|
|
|
|
In either case, the contents of the data portion of the connection
|
|
request is the data to return to the caller of NtConnectPort.
|
|
|
|
If the connection request is accepted, then two communication port
|
|
objects will be created and connected together. One will be
|
|
inserted in the client process' handle table and returned to the
|
|
client via the PortHandle parameter it specified on the
|
|
NtConnectPort service. The other will be inserted in the server
|
|
process' handle table and returned via the PortHandle parameter
|
|
specified on the NtCompleteConnectPort service. In addition the
|
|
two communication ports (client and server) will be linked together.
|
|
|
|
If the connection request is accepted, and the ServerView parameter
|
|
was specified, then the section handle is examined. If it is valid,
|
|
then the portion of the section described by the SectionOffset and
|
|
ViewSize fields will be mapped into both the client and server
|
|
process address spaces. The address in server's address space will
|
|
be returned in the ViewBase field. The address in the client's
|
|
address space will be returned in the ViewRemoteBase field. The
|
|
actual offset and size used to map the section will be returned in
|
|
the SectionOffset and ViewSize fields.
|
|
|
|
Communication port objects are temporary objects that have no names
|
|
and cannot be inherited. When either the client or server process
|
|
calls the !f NtClose service for a communication port, the port will
|
|
be deleted since there can never be more than one outstanding handle
|
|
for each communication port. The port object type specific delete
|
|
procedure will then be invoked. This delete procedure will examine
|
|
the communication port, and if it is connected to another
|
|
communication port, it will queue an LPC_PORT_CLOSED datagram to
|
|
that port's message queue. This will allow both the client and
|
|
server processes to notice when a port becomes disconnected, either
|
|
because of an explicit call to NtClose or an implicit call due to
|
|
process termination. In addition, the delete procedure will scan
|
|
the message queue of the port being closed and for each message
|
|
still in the queue, it will return an ERROR_PORT_CLOSED status to
|
|
any thread that is waiting for a reply to the message.
|
|
|
|
Arguments:
|
|
|
|
PortHandle - A pointer to a variable that will receive the server
|
|
communication port object handle value.
|
|
|
|
PortContext - An uninterpreted pointer that is stored in the
|
|
server communication port. This pointer is returned whenever
|
|
a message is received for this port.
|
|
|
|
ConnectionRequest - A pointer to a structure that describes the
|
|
connection request being accepted or rejected:
|
|
|
|
!b !u ConnectionRequest Structure
|
|
|
|
ULONG !f Length - Specifies the size of this data structure in
|
|
bytes.
|
|
|
|
!t CLIENT_ID !f ClientId - Specifies a structure that contains the
|
|
client identifier (CLIENT_ID) of the thread that sent the request.
|
|
|
|
!b !u ClientId Structure
|
|
|
|
ULONG !f UniqueProcessId - A unique value for each process
|
|
in the system.
|
|
|
|
ULONG !f UniqueThreadId - A unique value for each thread in the
|
|
system.
|
|
|
|
ULONG !f MessageId - A unique value that identifies the connection
|
|
request being completed.
|
|
|
|
ULONG PortAttributes - This field has no meaning for this service.
|
|
|
|
ULONG ClientViewSize - This field has no meaning for this service.
|
|
|
|
AcceptConnection - Specifies a boolean value which indicates where
|
|
the connection request is being accepted or rejected. A value
|
|
of TRUE means that the connection request is accepted and a
|
|
server communication port handle will be created and connected
|
|
to the client's communication port handle. A value of FALSE
|
|
means that the connection request is not accepted.
|
|
|
|
ServerView - A pointer to a structure that specifies the section that
|
|
the server process will use to send messages back to the client
|
|
process connected to this port.
|
|
|
|
!b !u ServerView Structure
|
|
|
|
ULONG !f Length - Specifies the size of this data structure in
|
|
bytes.
|
|
|
|
HANDLE !f SectionHandle - Specifies an open handle to a section
|
|
object.
|
|
|
|
ULONG !f SectionOffset - Specifies a field that will receive the
|
|
actual offset, in bytes, from the start of the section. The
|
|
initial value of this parameter specifies the byte offset
|
|
within the section that the client's view is based. The
|
|
value is rounded down to the next host page size boundary.
|
|
|
|
ULONG !f ViewSize - Specifies the size of the view, in bytes.
|
|
|
|
PVOID !f ViewBase - Specifies a field that will receive the base
|
|
address of the port memory in the server's address space.
|
|
|
|
PVOID !f ViewRemoteBase - Specifies a field that will receive
|
|
the base address of the server port's memory in the client's
|
|
address space. Used to generate pointers that are
|
|
meaningful to the client.
|
|
|
|
ClientView - An optional pointer to a structure that will receive
|
|
information about the client process' view in the server's
|
|
address space. The server process can use this information
|
|
to validate pointers it receives from the client process.
|
|
|
|
!b !u ClientView Structure
|
|
|
|
ULONG !f Length - Specifies the size of this data structure in
|
|
bytes.
|
|
|
|
PVOID !f ViewBase - Specifies a field that will receive the base
|
|
address of the client port's memory in the server's address
|
|
space.
|
|
|
|
ULONG !f ViewSize - Specifies a field that will receive the
|
|
size, in bytes, of the client's view in the server's address
|
|
space. If this field is zero, then client has no view in
|
|
the server's address space.
|
|
|
|
Return Value:
|
|
|
|
return-value - Description of conditions needed to return value. - or -
|
|
None.
|
|
|
|
--*/
|
|
{
|
|
PLPCP_PORT_OBJECT ConnectionPort;
|
|
PLPCP_PORT_OBJECT ServerPort;
|
|
PLPCP_PORT_OBJECT ClientPort;
|
|
PVOID ClientSectionToMap;
|
|
HANDLE Handle;
|
|
KPROCESSOR_MODE PreviousMode;
|
|
NTSTATUS Status;
|
|
ULONG ConnectionInfoLength;
|
|
PLPCP_MESSAGE Msg;
|
|
PLPCP_CONNECTION_MESSAGE ConnectMsg;
|
|
PORT_MESSAGE CapturedReplyMessage;
|
|
PVOID SectionToMap;
|
|
LARGE_INTEGER SectionOffset;
|
|
ULONG ViewSize;
|
|
PEPROCESS ClientProcess;
|
|
PETHREAD ClientThread;
|
|
PORT_VIEW CapturedServerView;
|
|
|
|
PAGED_CODE();
|
|
|
|
//
|
|
// Get previous processor mode and probe output arguments if necessary.
|
|
//
|
|
|
|
PreviousMode = KeGetPreviousMode();
|
|
if (PreviousMode != KernelMode) {
|
|
try {
|
|
ProbeForWriteHandle( PortHandle );
|
|
|
|
ProbeForRead( ConnectionRequest,
|
|
sizeof( *ConnectionRequest ),
|
|
sizeof( ULONG )
|
|
);
|
|
|
|
CapturedReplyMessage = *ConnectionRequest;
|
|
if (ARGUMENT_PRESENT( ServerView )) {
|
|
if (ServerView->Length != sizeof( *ServerView )) {
|
|
return( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
CapturedServerView = *ServerView;
|
|
ProbeForWrite( ServerView,
|
|
sizeof( *ServerView ),
|
|
sizeof( ULONG )
|
|
);
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT( ClientView )) {
|
|
if (ClientView->Length != sizeof( *ClientView )) {
|
|
return( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
ProbeForWrite( ClientView,
|
|
sizeof( *ClientView ),
|
|
sizeof( ULONG )
|
|
);
|
|
}
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
return( GetExceptionCode() );
|
|
}
|
|
}
|
|
else {
|
|
CapturedReplyMessage = *ConnectionRequest;
|
|
|
|
if (ARGUMENT_PRESENT( ServerView )) {
|
|
if (ServerView->Length != sizeof( *ServerView )) {
|
|
return( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
CapturedServerView = *ServerView;
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT( ClientView )) {
|
|
if (ClientView->Length != sizeof( *ClientView )) {
|
|
return( STATUS_INVALID_PARAMETER );
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Translate the ClientId from the connection request into a
|
|
// thread pointer. This is a referenced pointer to keep the thread
|
|
// from evaporating out from under us.
|
|
//
|
|
|
|
Status = PsLookupProcessThreadByCid( &CapturedReplyMessage.ClientId,
|
|
&ClientProcess,
|
|
&ClientThread
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// Acquire the mutex that gaurds the LpcReplyMessage field of
|
|
// the thread and get the pointer to the message that the thread
|
|
// is waiting for a reply to.
|
|
//
|
|
|
|
ExAcquireFastMutex( &LpcpLock );
|
|
|
|
//
|
|
// See if the thread is waiting for a reply to the connection request
|
|
// specified on this call. If not then a bogus connection request
|
|
// has been specified, so release the mutex, dereference the thread
|
|
// and return failure.
|
|
//
|
|
|
|
if (ClientThread->LpcReplyMessage == NULL ||
|
|
ClientThread->LpcReplyMessageId != CapturedReplyMessage.MessageId
|
|
) {
|
|
Msg = NULL;
|
|
}
|
|
else {
|
|
Msg = ClientThread->LpcReplyMessage;
|
|
ClientThread->LpcReplyMessage = NULL;
|
|
}
|
|
|
|
//
|
|
// Release the mutex that guards the field.
|
|
//
|
|
|
|
ClientThread->LpcReplyMessageId = 0;
|
|
ExReleaseFastMutex( &LpcpLock );
|
|
|
|
if ( !Msg ) {
|
|
LpcpPrint(( "%s Attempted AcceptConnectPort to Thread %lx (%s)\n",
|
|
PsGetCurrentProcess()->ImageFileName,
|
|
ClientThread,
|
|
THREAD_TO_PROCESS( ClientThread )->ImageFileName
|
|
));
|
|
LpcpPrint(( "failed. MessageId == %u\n", CapturedReplyMessage.MessageId ));
|
|
LpcpPrint(( " Thread MessageId == %u\n", ClientThread->LpcReplyMessageId ));
|
|
LpcpPrint(( " Thread Msg == %x\n", ClientThread->LpcReplyMessage ));
|
|
|
|
ObDereferenceObject( ClientProcess );
|
|
ObDereferenceObject( ClientThread );
|
|
return (STATUS_REPLY_MESSAGE_MISMATCH);
|
|
}
|
|
|
|
ConnectMsg = (PLPCP_CONNECTION_MESSAGE)(Msg + 1);
|
|
LpcpTrace(("Replying to Connect Msg %lx to Port %lx\n",
|
|
Msg, ConnectMsg->ClientPort->ConnectionPort ));
|
|
|
|
//
|
|
// Extract the client port address from the message
|
|
//
|
|
|
|
ClientPort = ConnectMsg->ClientPort;
|
|
|
|
//
|
|
// Get a pointer to the connection port from the client port.
|
|
//
|
|
|
|
ConnectionPort = ClientPort->ConnectionPort;
|
|
|
|
//
|
|
// Regardless of whether we are accepting or rejecting the connection,
|
|
// return the connection information to the waiting thread.
|
|
//
|
|
|
|
ConnectionInfoLength = CapturedReplyMessage.u1.s1.DataLength;
|
|
if (ConnectionInfoLength > ConnectionPort->MaxConnectionInfoLength) {
|
|
ConnectionInfoLength = ConnectionPort->MaxConnectionInfoLength;
|
|
}
|
|
|
|
Msg->Request.u1.s1.DataLength = (CSHORT)(sizeof( *ConnectMsg ) +
|
|
ConnectionInfoLength
|
|
);
|
|
Msg->Request.u1.s1.TotalLength = (CSHORT)(sizeof( *Msg ) +
|
|
Msg->Request.u1.s1.DataLength
|
|
);
|
|
Msg->Request.u2.s2.Type = LPC_REPLY;
|
|
Msg->Request.u2.s2.DataInfoOffset = 0;
|
|
Msg->Request.ClientId = CapturedReplyMessage.ClientId;
|
|
Msg->Request.MessageId = CapturedReplyMessage.MessageId;
|
|
Msg->Request.ClientViewSize = 0;
|
|
|
|
try {
|
|
RtlMoveMemory( ConnectMsg + 1,
|
|
(PCHAR)(ConnectionRequest + 1),
|
|
ConnectionInfoLength
|
|
);
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
Status = GetExceptionCode();
|
|
}
|
|
|
|
ClientSectionToMap = NULL;
|
|
if (AcceptConnection) {
|
|
|
|
//
|
|
// Allocate and initialize a server communication port object.
|
|
// Communication ports have no names, can not be inherited and
|
|
// are process private handles.
|
|
//
|
|
|
|
Status = ObCreateObject( PreviousMode,
|
|
LpcPortObjectType,
|
|
NULL,
|
|
PreviousMode,
|
|
NULL,
|
|
sizeof( LPCP_PORT_OBJECT ),
|
|
0,
|
|
0,
|
|
(PVOID *)&ServerPort
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
goto bailout;
|
|
}
|
|
|
|
RtlZeroMemory( ServerPort, sizeof( LPCP_PORT_OBJECT ) );
|
|
ServerPort->Length = sizeof( LPCP_PORT_OBJECT );
|
|
ServerPort->PortContext = PortContext;
|
|
ServerPort->Flags = SERVER_COMMUNICATION_PORT;
|
|
InitializeListHead( &ServerPort->LpcReplyChainHead );
|
|
InitializeListHead( &ServerPort->LpcDataInfoChainHead );
|
|
|
|
//
|
|
// Connect the newly created server communication port to the
|
|
// connection port with a referenced pointer. Prevents the
|
|
// connection port from going away until all of the communication
|
|
// ports have been closed.
|
|
//
|
|
|
|
ObReferenceObject( ConnectionPort );
|
|
ServerPort->ConnectionPort = ConnectionPort;
|
|
ServerPort->MaxMessageLength = ConnectionPort->MaxMessageLength;
|
|
|
|
//
|
|
// Connect the client and server communication ports together
|
|
// with unreferenced pointers. They are unreferenced so that
|
|
// the PortObjectType delete procedure will get called when a
|
|
// communication port is closed. If this were not the case then
|
|
// we would need a special NtClosePort system service in order
|
|
// to tear down a pair of connected communication ports.
|
|
//
|
|
|
|
ServerPort->ConnectedPort = ClientPort;
|
|
ClientPort->ConnectedPort = ServerPort;
|
|
|
|
ServerPort->Creator = PsGetCurrentThread()->Cid;
|
|
ClientPort->Creator = Msg->Request.ClientId;
|
|
|
|
//
|
|
// If the client has allocated a port memory section that is mapped
|
|
// into the client's address space, then map a view of the same section
|
|
// for the server process to see.
|
|
//
|
|
|
|
ExAcquireFastMutex( &LpcpLock );
|
|
ClientSectionToMap = ConnectMsg->SectionToMap;
|
|
ConnectMsg->SectionToMap = NULL;
|
|
ExReleaseFastMutex( &LpcpLock );
|
|
if (ClientSectionToMap) {
|
|
|
|
LARGE_INTEGER LargeSectionOffset;
|
|
|
|
LargeSectionOffset.LowPart = ConnectMsg->ClientView.SectionOffset;
|
|
LargeSectionOffset.HighPart = 0;
|
|
|
|
Status = MmMapViewOfSection( ClientSectionToMap,
|
|
PsGetCurrentProcess(),
|
|
&ServerPort->ClientSectionBase,
|
|
0,
|
|
0,
|
|
&LargeSectionOffset,
|
|
&ConnectMsg->ClientView.ViewSize,
|
|
ViewUnmap,
|
|
0,
|
|
PAGE_READWRITE
|
|
);
|
|
|
|
ConnectMsg->ClientView.SectionOffset = LargeSectionOffset.LowPart;
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
ConnectMsg->ClientView.ViewRemoteBase = ServerPort->ClientSectionBase;
|
|
}
|
|
else {
|
|
ObDereferenceObject( ServerPort );
|
|
}
|
|
}
|
|
|
|
//
|
|
// If the server process has allocated a port memory section for
|
|
// send data to the client on call back requests, map two views
|
|
// of that section, the first for the server process and the
|
|
// second view for the client process. Return the location of the
|
|
// server's view to the caller of this function. Return the
|
|
// client's view to the client process via the reply to the
|
|
// connection request.
|
|
//
|
|
|
|
if (NT_SUCCESS( Status ) && ARGUMENT_PRESENT( ServerView )) {
|
|
|
|
LARGE_INTEGER LargeSectionOffset;
|
|
|
|
LargeSectionOffset.LowPart = CapturedServerView.SectionOffset;
|
|
LargeSectionOffset.HighPart = 0;
|
|
Status = ZwMapViewOfSection( CapturedServerView.SectionHandle,
|
|
NtCurrentProcess(),
|
|
&ServerPort->ServerSectionBase,
|
|
0,
|
|
0,
|
|
&LargeSectionOffset,
|
|
&CapturedServerView.ViewSize,
|
|
ViewUnmap,
|
|
0,
|
|
PAGE_READWRITE
|
|
);
|
|
CapturedServerView.SectionOffset = LargeSectionOffset.LowPart;
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
CapturedServerView.ViewBase = ServerPort->ServerSectionBase;
|
|
Status = ObReferenceObjectByHandle( CapturedServerView.SectionHandle,
|
|
SECTION_MAP_READ |
|
|
SECTION_MAP_WRITE,
|
|
MmSectionObjectType,
|
|
PreviousMode,
|
|
(PVOID *)&SectionToMap,
|
|
NULL
|
|
);
|
|
if (NT_SUCCESS( Status )) {
|
|
SectionOffset.LowPart = CapturedServerView.SectionOffset;
|
|
SectionOffset.HighPart = 0;
|
|
ViewSize = CapturedServerView.ViewSize;
|
|
Status = MmMapViewOfSection( SectionToMap,
|
|
ClientProcess,
|
|
&ClientPort->ServerSectionBase,
|
|
0,
|
|
0,
|
|
&SectionOffset,
|
|
&ViewSize,
|
|
ViewUnmap,
|
|
0,
|
|
PAGE_READWRITE
|
|
);
|
|
if (NT_SUCCESS( Status )) {
|
|
CapturedServerView.ViewRemoteBase =
|
|
ClientPort->ServerSectionBase;
|
|
ConnectMsg->ServerView.ViewBase =
|
|
ClientPort->ServerSectionBase;
|
|
ConnectMsg->ServerView.ViewSize = ViewSize;
|
|
}
|
|
else {
|
|
ObDereferenceObject( ServerPort );
|
|
}
|
|
|
|
ObDereferenceObject( SectionToMap );
|
|
}
|
|
else {
|
|
ObDereferenceObject( ServerPort );
|
|
}
|
|
}
|
|
else {
|
|
ObDereferenceObject( ServerPort );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Insert the server communication port object in specified object
|
|
// table. Set port handle value if successful. If not
|
|
// successful, then the port will have been dereferenced, which
|
|
// will cause it to be freed, after our delete procedure is
|
|
// called. The delete procedure will undo the work done to
|
|
// initialize the port.
|
|
//
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
|
|
Status = ObInsertObject( ServerPort,
|
|
NULL,
|
|
PORT_ALL_ACCESS,
|
|
0,
|
|
(PVOID *)NULL,
|
|
&Handle
|
|
);
|
|
|
|
if (NT_SUCCESS( Status )) {
|
|
try {
|
|
if (ARGUMENT_PRESENT( ServerView )) {
|
|
*ServerView = CapturedServerView;
|
|
}
|
|
|
|
if (ARGUMENT_PRESENT( ClientView )) {
|
|
ClientView->ViewBase = ConnectMsg->ClientView.ViewRemoteBase;
|
|
ClientView->ViewSize = ConnectMsg->ClientView.ViewSize;
|
|
}
|
|
|
|
*PortHandle = Handle;
|
|
|
|
if (!ARGUMENT_PRESENT( PortContext )) {
|
|
ServerPort->PortContext = Handle;
|
|
}
|
|
ServerPort->ClientThread = ClientThread;
|
|
ExAcquireFastMutex( &LpcpLock );
|
|
ClientThread->LpcReplyMessage = Msg;
|
|
ExReleaseFastMutex( &LpcpLock );
|
|
ClientThread = NULL;
|
|
}
|
|
except( EXCEPTION_EXECUTE_HANDLER ) {
|
|
NtClose( Handle );
|
|
Status = GetExceptionCode();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
LpcpPrint(( "Refusing connection from %x.%x\n",
|
|
Msg->Request.ClientId.UniqueProcess,
|
|
Msg->Request.ClientId.UniqueThread
|
|
));
|
|
}
|
|
bailout:
|
|
|
|
if ( ClientSectionToMap ) {
|
|
ObDereferenceObject( ClientSectionToMap );
|
|
}
|
|
|
|
if (ClientThread != NULL) {
|
|
ExAcquireFastMutex( &LpcpLock );
|
|
ClientThread->LpcReplyMessage = Msg;
|
|
ExReleaseFastMutex( &LpcpLock );
|
|
|
|
if (AcceptConnection) {
|
|
LpcpPrint(( "LPC: Failing AcceptConnection with Status == %x\n", Status ));
|
|
}
|
|
|
|
LpcpPrepareToWakeClient( ClientThread );
|
|
|
|
//
|
|
// Wake up the thread that is waiting for an answer to its connection
|
|
// request inside of NtConnectPort.
|
|
//
|
|
|
|
KeReleaseSemaphore( &ClientThread->LpcReplySemaphore,
|
|
0,
|
|
1L,
|
|
FALSE
|
|
);
|
|
|
|
//
|
|
// Dereference client thread and return the system service status.
|
|
//
|
|
|
|
ObDereferenceObject( ClientThread );
|
|
}
|
|
|
|
ObDereferenceObject( ClientProcess );
|
|
return( Status );
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NtCompleteConnectPort(
|
|
IN HANDLE PortHandle
|
|
)
|
|
{
|
|
PLPCP_PORT_OBJECT PortObject;
|
|
KPROCESSOR_MODE PreviousMode;
|
|
NTSTATUS Status;
|
|
PETHREAD ClientThread;
|
|
|
|
PAGED_CODE();
|
|
//
|
|
// Get previous processor mode
|
|
//
|
|
|
|
PreviousMode = KeGetPreviousMode();
|
|
|
|
//
|
|
// Reference the port object by handle
|
|
//
|
|
|
|
Status = LpcpReferencePortObject( PortHandle,
|
|
0,
|
|
PreviousMode,
|
|
&PortObject
|
|
);
|
|
if (!NT_SUCCESS( Status )) {
|
|
return( Status );
|
|
}
|
|
|
|
//
|
|
// Error if a port type is invalid.
|
|
//
|
|
|
|
if ((PortObject->Flags & PORT_TYPE) != SERVER_COMMUNICATION_PORT) {
|
|
ObDereferenceObject( PortObject );
|
|
return( STATUS_INVALID_PORT_HANDLE );
|
|
}
|
|
|
|
if (PortObject->ClientThread == NULL) {
|
|
ObDereferenceObject( PortObject );
|
|
return( STATUS_INVALID_PARAMETER );
|
|
}
|
|
|
|
ClientThread = PortObject->ClientThread;
|
|
PortObject->ClientThread = NULL;
|
|
|
|
LpcpPrepareToWakeClient( ClientThread );
|
|
|
|
//
|
|
// Wake up the thread that is waiting for an answer to its connection
|
|
// request inside of NtConnectPort.
|
|
//
|
|
|
|
KeReleaseSemaphore( &ClientThread->LpcReplySemaphore,
|
|
0,
|
|
1L,
|
|
FALSE
|
|
);
|
|
|
|
//
|
|
// Dereference client thread and return the system service status.
|
|
//
|
|
|
|
ObDereferenceObject( ClientThread );
|
|
ObDereferenceObject( PortObject );
|
|
return( Status );
|
|
}
|
|
|
|
|
|
|
|
VOID
|
|
LpcpPrepareToWakeClient(
|
|
IN PETHREAD ClientThread
|
|
)
|
|
{
|
|
PAGED_CODE();
|
|
//
|
|
// Remove thread from rundown list as we are sending a reply
|
|
//
|
|
|
|
ExAcquireFastMutex( &LpcpLock );
|
|
if (!ClientThread->LpcExitThreadCalled && !IsListEmpty( &ClientThread->LpcReplyChain )) {
|
|
RemoveEntryList( &ClientThread->LpcReplyChain );
|
|
InitializeListHead( &ClientThread->LpcReplyChain );
|
|
}
|
|
|
|
ExReleaseFastMutex( &LpcpLock );
|
|
return;
|
|
}
|