- Silence TCPIP.
[reactos.git] / reactos / ntoskrnl / lpc / connect.c
index fe525e3..c2e5a50 100644 (file)
-/* $Id: connect.c,v 1.1 2000/06/04 17:27:39 ea Exp $
- * 
+/* $Id$
+ *
  * COPYRIGHT:       See COPYING in the top level directory
  * PROJECT:         ReactOS kernel
  * FILE:            ntoskrnl/lpc/connect.c
  * PURPOSE:         Communication mechanism
- * PROGRAMMER:      David Welch (welch@cwcom.net)
- * UPDATE HISTORY:
- *                  Created 22/05/98
+ *
+ * PROGRAMMERS:     David Welch (welch@cwcom.net)
  */
 
 /* INCLUDES *****************************************************************/
 
-#include <ddk/ntddk.h>
-#include <internal/ob.h>
-#include <string.h>
-#include <internal/string.h>
-#include <internal/port.h>
-#include <internal/dbg.h>
-
+#include <ntoskrnl.h>
 #define NDEBUG
 #include <internal/debug.h>
 
+/* FUNCTIONS *****************************************************************/
 
 /**********************************************************************
  * NAME                                                        EXPORTED
- *     NtConnectPort@32
- *     
+ *     EiConnectPort/12
+ *
  * DESCRIPTION
- *     Connect to a named port and wait for the other side to 
- *     accept the connection.
+ *
+ * ARGUMENTS
+ *
+ * RETURN VALUE
+ */
+NTSTATUS STDCALL
+EiConnectPort(IN PEPORT* ConnectedPort,
+             IN PEPORT NamedPort,
+             IN PSECTION_OBJECT Section,
+             IN LARGE_INTEGER SectionOffset,
+             IN ULONG ViewSize,
+             OUT PVOID* ClientSendViewBase,
+             OUT PVOID* ServerSendViewBase,
+             OUT PULONG ReceiveViewSize,
+             OUT PVOID* ReceiveViewBase,
+             OUT PULONG MaximumMessageSize,
+             IN OUT PVOID ConnectData,
+             IN OUT PULONG ConnectDataLength)
+{
+  PEPORT_CONNECT_REQUEST_MESSAGE RequestMessage;
+  ULONG RequestConnectDataLength;
+  PEPORT OurPort;
+  PQUEUEDMESSAGE Reply;
+  PEPORT_CONNECT_REPLY_MESSAGE CReply;
+  NTSTATUS Status;
+  KIRQL oldIrql;
+
+  if (ConnectDataLength == NULL)
+    {
+      RequestConnectDataLength = 0;
+    }
+  else
+    {
+      RequestConnectDataLength = *ConnectDataLength;
+    }
+
+  /*
+   * Create a port to represent our side of the connection
+   */
+  Status = ObCreateObject (KernelMode,
+                          LpcPortObjectType,
+                          NULL,
+                          KernelMode,
+                          NULL,
+                          sizeof(EPORT),
+                          0,
+                          0,
+                          (PVOID*)&OurPort);
+  if (!NT_SUCCESS(Status))
+    {
+      return (Status);
+    }
+  LpcpInitializePort(OurPort, EPORT_TYPE_CLIENT_COMM_PORT, NamedPort);
+
+  /*
+   * Allocate a request message.
+   */
+  RequestMessage = ExAllocatePool(NonPagedPool,
+                                 sizeof(EPORT_CONNECT_REQUEST_MESSAGE) +
+                                 RequestConnectDataLength);
+  if (RequestMessage == NULL)
+    {
+      ObDereferenceObject(OurPort);
+      return(STATUS_NO_MEMORY);
+    }
+
+  /*
+   * Initialize the request message.
+   */
+  RequestMessage->MessageHeader.u1.s1.DataLength =
+    sizeof(EPORT_CONNECT_REQUEST_MESSAGE) + RequestConnectDataLength -
+    sizeof(PORT_MESSAGE);
+  RequestMessage->MessageHeader.u1.s1.TotalLength =
+    sizeof(EPORT_CONNECT_REQUEST_MESSAGE) + RequestConnectDataLength;
+  DPRINT("RequestMessageSize %d\n",
+        RequestMessage->MessageHeader.u1.s1.TotalLength);
+  RequestMessage->MessageHeader.ClientViewSize = 0;
+  RequestMessage->ConnectingProcess = PsGetCurrentProcess();
+  ObReferenceObjectByPointer(RequestMessage->ConnectingProcess,
+                            PROCESS_VM_OPERATION,
+                            NULL,
+                            KernelMode);
+  RequestMessage->SendSectionObject = (struct _SECTION_OBJECT*)Section;
+  RequestMessage->SendSectionOffset = SectionOffset;
+  RequestMessage->SendViewSize = ViewSize;
+  RequestMessage->ConnectDataLength = RequestConnectDataLength;
+  if (RequestConnectDataLength > 0)
+    {
+      memcpy(RequestMessage->ConnectData, ConnectData,
+            RequestConnectDataLength);
+    }
+
+  /*
+   * Queue the message to the named port
+   */
+  EiReplyOrRequestPort(NamedPort,
+                      &RequestMessage->MessageHeader,
+                      LPC_CONNECTION_REQUEST,
+                      OurPort);
+  KeReleaseSemaphore(&NamedPort->Semaphore, IO_NO_INCREMENT, 1, FALSE);
+  ExFreePool(RequestMessage);
+
+  /*
+   * Wait for them to accept our connection
+   */
+  KeWaitForSingleObject(&OurPort->Semaphore,
+                       UserRequest,
+                       UserMode,
+                       FALSE,
+                       NULL);
+
+  /*
+   * Dequeue the response
+   */
+  KeAcquireSpinLock (&OurPort->Lock, &oldIrql);
+  Reply = EiDequeueMessagePort (OurPort);
+  KeReleaseSpinLock (&OurPort->Lock, oldIrql);
+  CReply = (PEPORT_CONNECT_REPLY_MESSAGE)&Reply->Message;
+
+  /*
+   * Do some initial cleanup.
+   */
+  ObDereferenceObject(PsGetCurrentProcess());
+
+  /*
+   * Check for connection refusal.
+   */
+  if (CReply->MessageHeader.u2.s2.Type == LPC_CONNECTION_REFUSED)
+    {
+      ObDereferenceObject(OurPort);
+      ExFreePool(Reply);
+      /*
+       * FIXME: Check what NT does here. Giving the user data back on
+       * connect failure sounds reasonable; it probably wouldn't break
+       * anything anyway.
+       */
+      if (ConnectDataLength != NULL)
+       {
+         *ConnectDataLength = CReply->ConnectDataLength;
+         memcpy(ConnectData, CReply->ConnectData, CReply->ConnectDataLength);
+       }
+      return(STATUS_PORT_CONNECTION_REFUSED);
+    }
+
+  /*
+   * Otherwise we are connected. Copy data back to the client.
+   */
+  *ServerSendViewBase = CReply->SendServerViewBase;
+  *ReceiveViewSize = CReply->ReceiveClientViewSize;
+  *ReceiveViewBase = CReply->ReceiveClientViewBase;
+  *MaximumMessageSize = CReply->MaximumMessageSize;
+  if (ConnectDataLength != NULL)
+    {
+      *ConnectDataLength = CReply->ConnectDataLength;
+      memcpy(ConnectData, CReply->ConnectData, CReply->ConnectDataLength);
+    }
+
+  /*
+   * Create our view of the send section object.
+   */
+  if (Section != NULL)
+    {
+      *ClientSendViewBase = 0;
+      Status = MmMapViewOfSection(Section,
+                                 PsGetCurrentProcess(),
+                                 ClientSendViewBase,
+                                 0,
+                                 ViewSize,
+                                 &SectionOffset,
+                                 &ViewSize,
+                                 ViewUnmap,
+                                 0 /* MEM_TOP_DOWN? */,
+                                 PAGE_READWRITE);
+      if (!NT_SUCCESS(Status))
+       {
+         /* FIXME: Cleanup here. */
+         return(Status);
+       }
+    }
+
+  /*
+   * Do the final initialization of our port.
+   */
+  OurPort->State = EPORT_CONNECTED_CLIENT;
+
+  /*
+   * Cleanup.
+   */
+  ExFreePool(Reply);
+  *ConnectedPort = OurPort;
+  return(STATUS_SUCCESS);
+}
+
+/**********************************************************************
+ * NAME                                                        EXPORTED
+ *     NtConnectPort/8
+ *
+ * DESCRIPTION
+ *     Connect to a named port and wait for the other side to
+ *     accept or reject the connection request.
  *
  * ARGUMENTS
  *     ConnectedPort
  *     MaxMessageSize
  *     ConnectInfo
  *     UserConnectInfoLength
- * 
+ *
  * RETURN VALUE
- * 
+ *
+ * @unimplemented
  */
-NTSTATUS
-STDCALL
-NtConnectPort (
-       PHANDLE                         ConnectedPort,
-       PUNICODE_STRING                 PortName,
-       PSECURITY_QUALITY_OF_SERVICE    Qos,
-       PLPC_SECTION_WRITE              WriteMap,
-       PLPC_SECTION_READ               ReadMap,
-       PULONG                          MaxMessageSize,
-       PVOID                           ConnectInfo,
-       PULONG                          UserConnectInfoLength
-       )
+NTSTATUS STDCALL
+NtConnectPort (PHANDLE                         UnsafeConnectedPortHandle,
+              PUNICODE_STRING                  PortName,
+              PSECURITY_QUALITY_OF_SERVICE     Qos,
+              PPORT_VIEW               UnsafeWriteMap,
+              PREMOTE_PORT_VIEW                UnsafeReadMap,
+              PULONG                           UnsafeMaximumMessageSize,
+              PVOID                            UnsafeConnectData,
+              PULONG                           UnsafeConnectDataLength)
 {
-       NTSTATUS        Status;
-       PEPORT          NamedPort;
-       PEPORT          OurPort;
-       HANDLE          OurPortHandle;
-       PLPC_MESSAGE    Request;
-       PQUEUEDMESSAGE  Reply;
-       ULONG           ConnectInfoLength;
-       KIRQL           oldIrql;
-   
-       DPRINT("PortName %x\n", PortName);
-       DPRINT("NtConnectPort(PortName %S)\n", PortName->Buffer);
-   
-       /*
-        * Copy in user parameters
-        */
-       memcpy (
-               & ConnectInfoLength, 
-               UserConnectInfoLength, 
-               sizeof (*UserConnectInfoLength)
-               );
-       /*
-        * Get access to the port
-        */
-       Status = ObReferenceObjectByName (
-                       PortName,
-                       0,
-                       NULL,
-                       PORT_ALL_ACCESS,  /* DesiredAccess */
-                       ExPortType,
-                       UserMode,
-                       NULL,
-                       (PVOID *) & NamedPort
-                       );
-       if (!NT_SUCCESS(Status))
+  HANDLE ConnectedPortHandle;
+  PORT_VIEW WriteMap;
+  REMOTE_PORT_VIEW ReadMap;
+  ULONG MaximumMessageSize;
+  PVOID ConnectData = NULL;
+  ULONG ConnectDataLength = 0;
+  PSECTION_OBJECT SectionObject;
+  LARGE_INTEGER SectionOffset;
+  PEPORT ConnectedPort;
+  KPROCESSOR_MODE PreviousMode;
+  NTSTATUS Status = STATUS_SUCCESS;
+  PEPORT NamedPort;
+  
+  PreviousMode = ExGetPreviousMode();
+  
+  if (PreviousMode != KernelMode)
+    {
+      _SEH_TRY
+        {
+          ProbeForWriteHandle(UnsafeConnectedPortHandle);
+          if (UnsafeMaximumMessageSize != NULL)
+            {
+              ProbeForWriteUlong(UnsafeMaximumMessageSize);
+            }
+        }
+      _SEH_HANDLE
+        {
+          Status = _SEH_GetExceptionCode();
+        }
+      _SEH_END;
+      
+      if (!NT_SUCCESS(Status))
+        {
+          return Status;
+        }
+    }
+
+  /*
+   * Copy in write map and partially validate.
+   */
+  if (UnsafeWriteMap != NULL)
+    {
+      if (PreviousMode != KernelMode)
+        {
+          _SEH_TRY
+            {
+              ProbeForWrite(UnsafeWriteMap,
+                            sizeof(PORT_VIEW),
+                            1);
+              RtlCopyMemory(&WriteMap,
+                            UnsafeWriteMap,
+                            sizeof(PORT_VIEW));
+            }
+          _SEH_HANDLE
+            {
+              Status = _SEH_GetExceptionCode();
+            }
+          _SEH_END;
+
+          if (!NT_SUCCESS(Status))
+            {
+              return Status;
+            }
+        }
+      else
+        {
+          RtlCopyMemory(&WriteMap,
+                        UnsafeWriteMap,
+                        sizeof(PORT_VIEW));
+        }
+
+      if (WriteMap.Length != sizeof(PORT_VIEW))
+       {
+         return(STATUS_INVALID_PARAMETER_4);
+       }
+      SectionOffset.QuadPart = WriteMap.SectionOffset;
+    }
+  else
+    {
+      WriteMap.SectionHandle = INVALID_HANDLE_VALUE;
+    }
+
+  /*
+   * Handle connection data.
+   */
+  if (UnsafeConnectData)
+    {
+      if (PreviousMode != KernelMode)
+        {
+          _SEH_TRY
+            {
+              ConnectDataLength = ProbeForReadUlong(UnsafeConnectDataLength);
+            }
+          _SEH_HANDLE
+            {
+              Status = _SEH_GetExceptionCode();
+            }
+          _SEH_END;
+
+          if (!NT_SUCCESS(Status))
+            {
+              return Status;
+            }
+        }
+      else
+        {
+          ConnectDataLength = *UnsafeConnectDataLength;
+        }
+
+      if (ConnectDataLength != 0)
+        {
+          ConnectData = ExAllocatePool(NonPagedPool, ConnectDataLength);
+          if (ConnectData == NULL)
+            {
+              return(STATUS_NO_MEMORY);
+            }
+
+          if (PreviousMode != KernelMode)
+            {
+              _SEH_TRY
+                {
+                  ProbeForWriteUlong(UnsafeConnectData);
+                  RtlCopyMemory(ConnectData,
+                                UnsafeConnectData,
+                                ConnectDataLength);
+                }
+              _SEH_HANDLE
+                {
+                  Status = _SEH_GetExceptionCode();
+                }
+              _SEH_END;
+
+              if (!NT_SUCCESS(Status))
+                {
+                  ExFreePool(ConnectData);
+                  return Status;
+                }
+            }
+          else
+            {
+              RtlCopyMemory(ConnectData,
+                            UnsafeConnectData,
+                            ConnectDataLength);
+            }
+        }
+    }
+
+  /*
+   * Reference the named port.
+   */
+  Status = ObReferenceObjectByName (PortName,
+                                    0,
+                                    NULL,
+                                    PORT_ALL_ACCESS,  /* DesiredAccess */
+                                    LpcPortObjectType,
+                                    PreviousMode,
+                                    NULL,
+                                    (PVOID*)&NamedPort);
+  if (!NT_SUCCESS(Status))
+    {
+      if (KeGetPreviousMode() != KernelMode)
+       {
+         ExFreePool(ConnectData);
+       }
+      return(Status);
+    }
+
+  /*
+   * Reference the send section object.
+   */
+  if (WriteMap.SectionHandle != INVALID_HANDLE_VALUE)
+    {
+      Status = ObReferenceObjectByHandle(WriteMap.SectionHandle,
+                                        SECTION_MAP_READ | SECTION_MAP_WRITE,
+                                        MmSectionObjectType,
+                                        PreviousMode,
+                                        (PVOID*)&SectionObject,
+                                        NULL);
+      if (!NT_SUCCESS(Status))
        {
-               DPRINT("Failed to reference named port (status %x)\n", Status);
-               return (Status);
+         ObDereferenceObject(NamedPort);
+         if (KeGetPreviousMode() != KernelMode)
+           {
+             ExFreePool(ConnectData);
+           }
+         return(Status);
        }
-       /*
-        * Create a port to represent our side of the connection
-        */
-       OurPort = ObCreateObject (
-                       & OurPortHandle,
-                       PORT_ALL_ACCESS,
-                       NULL,
-                       ExPortType
-                       );
-       NiInitializePort(OurPort);
-       /*
-        * Create a request message
-        */
-       DPRINT("Creating request message\n");
-   
-       Request = ExAllocatePool (
-                       NonPagedPool,
-                       (sizeof (LPC_MESSAGE) + ConnectInfoLength)
-                       );
-   
-       Request->DataSize = ConnectInfoLength;
-       Request->MessageSize = sizeof(LPC_MESSAGE) + ConnectInfoLength;
-       Request->SharedSectionSize = 0;
-       if (    (ConnectInfo != NULL)
-               && (ConnectInfoLength > 0)
-               )
+    }
+  else
+    {
+      SectionObject = NULL;
+    }
+
+  /*
+   * Do the connection establishment.
+   */
+  Status = EiConnectPort(&ConnectedPort,
+                        NamedPort,
+                        SectionObject,
+                        SectionOffset,
+                        WriteMap.ViewSize,
+                        &WriteMap.ViewBase,
+                        &WriteMap.ViewRemoteBase,
+                        &ReadMap.ViewSize,
+                        &ReadMap.ViewBase,
+                        &MaximumMessageSize,
+                        ConnectData,
+                        &ConnectDataLength);
+  if (!NT_SUCCESS(Status))
+    {
+      /* FIXME: Again, check what NT does here. */
+      if (UnsafeConnectDataLength != NULL)
        {
-               memcpy (
-                       (PVOID) (Request + 1),
-                       ConnectInfo,
-                       ConnectInfoLength
-                       );
+         if (PreviousMode != KernelMode)
+           {
+              _SEH_TRY
+                {
+                  RtlCopyMemory(UnsafeConnectData,
+                                ConnectData,
+                                ConnectDataLength);
+                  *UnsafeConnectDataLength = ConnectDataLength;
+                }
+              _SEH_HANDLE
+                {
+                  Status = _SEH_GetExceptionCode();
+                }
+              _SEH_END;
+           }
+         else
+           {
+               RtlCopyMemory(UnsafeConnectData,
+                             ConnectData,
+                             ConnectDataLength);
+               *UnsafeConnectDataLength = ConnectDataLength;
+           }
+
+          ExFreePool(ConnectData);
        }
-       /*
-        * Queue the message to the named port
-        */
-       DPRINT("Queuing message\n");
-   
-       EiReplyOrRequestPort (
-               NamedPort,
-               Request,
-               LPC_CONNECTION_REQUEST,
-               OurPort
-               );
-       KeSetEvent (
-               & NamedPort->Event,
-               IO_NO_INCREMENT,
-               FALSE
-               );
-   
-       DPRINT("Waiting for connection completion\n");
-   
-       /*
-        * Wait for them to accept our connection
-        */
-       KeWaitForSingleObject (
-               & OurPort->Event,
-               UserRequest,
-               UserMode,
-               FALSE,
-               NULL
-               );
-
-       DPRINT("Received connection completion\n");
-       KeAcquireSpinLock (
-               & OurPort->Lock,
-               & oldIrql
-               );
-       Reply = EiDequeueMessagePort (OurPort);
-       KeReleaseSpinLock (
-               & OurPort->Lock,
-               oldIrql
-               );
-       memcpy (
-               ConnectInfo, 
-               Reply->MessageData,
-               Reply->Message.DataSize
-               );
-       *UserConnectInfoLength = Reply->Message.DataSize;
-   
-       if (Reply->Message.MessageType == LPC_CONNECTION_REFUSED)
+      return(Status);
+    }
+
+  /*
+   * Do some initial cleanup.
+   */
+  if (SectionObject != NULL)
+    {
+      ObDereferenceObject(SectionObject);
+      SectionObject = NULL;
+    }
+  ObDereferenceObject(NamedPort);
+  NamedPort = NULL;
+
+  /*
+   * Copy the data back to the caller.
+   */
+
+  if (UnsafeConnectDataLength != NULL)
+    {
+      if (PreviousMode != KernelMode)
        {
-               ObDereferenceObject (NamedPort);
-               ObDereferenceObject (OurPort);
-               ZwClose (OurPortHandle);
-               ExFreePool (Request);
-               ExFreePool (Reply);
-               return (STATUS_UNSUCCESSFUL);
+          _SEH_TRY
+            {
+              *UnsafeConnectDataLength = ConnectDataLength;
+              
+              if (ConnectData != NULL)
+                {
+                  RtlCopyMemory(UnsafeConnectData,
+                                ConnectData,
+                                ConnectDataLength);
+                }
+            }
+          _SEH_HANDLE
+            {
+              Status = _SEH_GetExceptionCode();
+            }
+          _SEH_END;
+
+         if (!NT_SUCCESS(Status))
+           {
+              if (ConnectData != NULL)
+                {
+                  ExFreePool(ConnectData);
+                }
+              return(Status);
+           }
        }
-   
-       OurPort->State = EPORT_CONNECTED_CLIENT;
-       *ConnectedPort = OurPortHandle;   
-       ExFreePool (Reply);
-       ExFreePool (Request);
-   
-       DPRINT("Exited successfully\n");
-   
-       return (STATUS_SUCCESS);
+      else
+        {
+          *UnsafeConnectDataLength = ConnectDataLength;
+          
+          if (ConnectData != NULL)
+            {
+              RtlCopyMemory(UnsafeConnectData,
+                            ConnectData,
+                            ConnectDataLength);
+            }
+        }
+
+      if (ConnectData != NULL)
+       {
+         ExFreePool(ConnectData);
+       }
+    }
+  Status = ObInsertObject(ConnectedPort,
+                         NULL,
+                         PORT_ALL_ACCESS,
+                         0,
+                         NULL,
+                         &ConnectedPortHandle);
+  if (!NT_SUCCESS(Status))
+    {
+      return(Status);
+    }
+
+  if (PreviousMode != KernelMode)
+    {
+      _SEH_TRY
+        {
+          *UnsafeConnectedPortHandle = ConnectedPortHandle;
+          
+          if (UnsafeWriteMap != NULL)
+            {
+              RtlCopyMemory(UnsafeWriteMap,
+                            &WriteMap,
+                            sizeof(PORT_VIEW));
+            }
+
+          if (UnsafeReadMap != NULL)
+            {
+              RtlCopyMemory(UnsafeReadMap,
+                            &ReadMap,
+                            sizeof(REMOTE_PORT_VIEW));
+            }
+
+          if (UnsafeMaximumMessageSize != NULL)
+            {
+              *UnsafeMaximumMessageSize = MaximumMessageSize;
+            }
+        }
+      _SEH_HANDLE
+        {
+          Status = _SEH_GetExceptionCode();
+        }
+      _SEH_END;
+      
+      if (!NT_SUCCESS(Status))
+        {
+          return Status;
+        }
+    }
+  else
+    {
+      *UnsafeConnectedPortHandle = ConnectedPortHandle;
+      
+      if (UnsafeWriteMap != NULL)
+        {
+          RtlCopyMemory(UnsafeWriteMap,
+                        &WriteMap,
+                        sizeof(PORT_VIEW));
+        }
+
+      if (UnsafeReadMap != NULL)
+        {
+          RtlCopyMemory(UnsafeReadMap,
+                        &ReadMap,
+                        sizeof(REMOTE_PORT_VIEW));
+        }
+
+      if (UnsafeMaximumMessageSize != NULL)
+        {
+          *UnsafeMaximumMessageSize = MaximumMessageSize;
+        }
+    }
+
+  /*
+   * All done.
+   */
+
+  return(STATUS_SUCCESS);
 }
 
 
 /**********************************************************************
  * NAME                                                        EXPORTED
- *     NtAcceptConnectPort@24
+ *     NtAcceptConnectPort/6
  *
  * DESCRIPTION
  *
@@ -210,94 +643,291 @@ NtConnectPort (
  *     ReadMap
  *
  * RETURN VALUE
- *
  */
-EXPORTED
-NTSTATUS
-STDCALL
-NtAcceptConnectPort (
-       PHANDLE                 ServerPortHandle,
-       HANDLE                  NamedPortHandle,
-       PLPC_MESSAGE            LpcMessage,
-       BOOLEAN                 AcceptIt,
-       PLPC_SECTION_WRITE      WriteMap,
-       PLPC_SECTION_READ       ReadMap
-       )
+/*EXPORTED*/ NTSTATUS STDCALL
+NtAcceptConnectPort (PHANDLE                   ServerPortHandle,
+                    HANDLE                     NamedPortHandle,
+                    PPORT_MESSAGE              LpcMessage,
+                    BOOLEAN                    AcceptIt,
+                    PPORT_VIEW WriteMap,
+                    PREMOTE_PORT_VIEW  ReadMap)
 {
-       NTSTATUS        Status;
-       PEPORT          NamedPort;
-       PEPORT          OurPort = NULL;
-       PQUEUEDMESSAGE  ConnectionRequest;
-       KIRQL           oldIrql;
-   
-       Status = ObReferenceObjectByHandle (
-                       NamedPortHandle,
-                       PORT_ALL_ACCESS,
-                       ExPortType,
-                       UserMode,
-                       (PVOID *) & NamedPort,
-                       NULL
-                       );
-       if (!NT_SUCCESS(Status))
+  NTSTATUS     Status;
+  PEPORT               NamedPort;
+  PEPORT               OurPort = NULL;
+  PQUEUEDMESSAGE       ConnectionRequest;
+  KIRQL                oldIrql;
+  PEPORT_CONNECT_REQUEST_MESSAGE CRequest;
+  PEPORT_CONNECT_REPLY_MESSAGE CReply;
+  ULONG Size;
+  KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
+
+  Size = sizeof(EPORT_CONNECT_REPLY_MESSAGE);
+  if (LpcMessage)
+  {
+     Size += LpcMessage->u1.s1.DataLength;
+  }
+
+  CReply = ExAllocatePool(NonPagedPool, Size);
+  if (CReply == NULL)
+    {
+      return(STATUS_NO_MEMORY);
+    }
+
+  Status = ObReferenceObjectByHandle(NamedPortHandle,
+                                    PORT_ALL_ACCESS,
+                                    LpcPortObjectType,
+                                    PreviousMode,
+                                    (PVOID*)&NamedPort,
+                                    NULL);
+  if (!NT_SUCCESS(Status))
+    {
+      ExFreePool(CReply);
+      return (Status);
+    }
+
+  /*
+   * Create a port object for our side of the connection
+   */
+  if (AcceptIt)
+    {
+      Status = ObCreateObject(PreviousMode,
+                             LpcPortObjectType,
+                             NULL,
+                             PreviousMode,
+                             NULL,
+                             sizeof(EPORT),
+                             0,
+                             0,
+                             (PVOID*)&OurPort);
+      if (!NT_SUCCESS(Status))
+       {
+         ExFreePool(CReply);
+         ObDereferenceObject(NamedPort);
+         return(Status);
+       }
+
+      Status = ObInsertObject ((PVOID)OurPort,
+                              NULL,
+                              PORT_ALL_ACCESS,
+                              0,
+                              NULL,
+                              ServerPortHandle);
+      if (!NT_SUCCESS(Status))
+       {
+         ObDereferenceObject(OurPort);
+         ExFreePool(CReply);
+         ObDereferenceObject(NamedPort);
+         return(Status);
+       }
+
+      LpcpInitializePort(OurPort, EPORT_TYPE_SERVER_COMM_PORT, NamedPort);
+    }
+
+  /*
+   * Dequeue the connection request
+   */
+  KeAcquireSpinLock(&NamedPort->Lock, &oldIrql);
+  ConnectionRequest = EiDequeueConnectMessagePort (NamedPort);
+  KeReleaseSpinLock(&NamedPort->Lock, oldIrql);
+  CRequest = (PEPORT_CONNECT_REQUEST_MESSAGE)(&ConnectionRequest->Message);
+
+  /*
+   * Prepare the reply.
+   */
+  if (LpcMessage != NULL)
+    {
+      memcpy(&CReply->MessageHeader, LpcMessage, sizeof(PORT_MESSAGE));
+      memcpy(&CReply->ConnectData, (PVOID)(LpcMessage + 1),
+            LpcMessage->u1.s1.DataLength);
+      CReply->MessageHeader.u1.s1.TotalLength =
+       sizeof(EPORT_CONNECT_REPLY_MESSAGE) + LpcMessage->u1.s1.DataLength;
+      CReply->MessageHeader.u1.s1.DataLength = CReply->MessageHeader.u1.s1.TotalLength -
+       sizeof(PORT_MESSAGE);
+      CReply->ConnectDataLength = LpcMessage->u1.s1.DataLength;
+    }
+  else
+    {
+      CReply->MessageHeader.u1.s1.TotalLength = sizeof(EPORT_CONNECT_REPLY_MESSAGE);
+      CReply->MessageHeader.u1.s1.DataLength = sizeof(EPORT_CONNECT_REPLY_MESSAGE) -
+       sizeof(PORT_MESSAGE);
+      CReply->ConnectDataLength = 0;
+    }
+  if (!AcceptIt)
+    {
+      EiReplyOrRequestPort(ConnectionRequest->Sender,
+                          &CReply->MessageHeader,
+                          LPC_CONNECTION_REFUSED,
+                          NamedPort);
+      KeReleaseSemaphore(&ConnectionRequest->Sender->Semaphore,
+                        IO_NO_INCREMENT,
+                        1,
+                        FALSE);
+      ObDereferenceObject(ConnectionRequest->Sender);
+      ExFreePool(ConnectionRequest);
+      ExFreePool(CReply);
+      ObDereferenceObject(NamedPort);
+      return (STATUS_SUCCESS);
+    }
+
+  /*
+   * Prepare the connection.
+   */
+  if (WriteMap != NULL)
+    {
+      PSECTION_OBJECT SectionObject;
+      LARGE_INTEGER SectionOffset;
+
+      Status = ObReferenceObjectByHandle(WriteMap->SectionHandle,
+                                        SECTION_MAP_READ | SECTION_MAP_WRITE,
+                                        MmSectionObjectType,
+                                        PreviousMode,
+                                        (PVOID*)&SectionObject,
+                                        NULL);
+      if (!NT_SUCCESS(Status))
+       {
+         return(Status);
+       }
+
+      SectionOffset.QuadPart = WriteMap->SectionOffset;
+      WriteMap->ViewRemoteBase = 0;
+      CReply->ReceiveClientViewSize = WriteMap->ViewSize;
+      Status = MmMapViewOfSection(SectionObject,
+                                 CRequest->ConnectingProcess,
+                                 &WriteMap->ViewRemoteBase,
+                                 0,
+                                 CReply->ReceiveClientViewSize,
+                                 &SectionOffset,
+                                 &CReply->ReceiveClientViewSize,
+                                 ViewUnmap,
+                                 0 /* MEM_TOP_DOWN? */,
+                                 PAGE_READWRITE);
+      if (!NT_SUCCESS(Status))
        {
-               return (Status);
+         return(Status);
        }
-       /*
-        * Create a port object for our side of the connection
-        */
-       if (AcceptIt == 1)
+
+      WriteMap->ViewBase = 0;
+      Status = MmMapViewOfSection(SectionObject,
+                                 PsGetCurrentProcess(),
+                                 &WriteMap->ViewBase,
+                                 0,
+                                 WriteMap->ViewSize,
+                                 &SectionOffset,
+                                 &WriteMap->ViewSize,
+                                 ViewUnmap,
+                                 0 /* MEM_TOP_DOWN? */,
+                                 PAGE_READWRITE);
+      if (!NT_SUCCESS(Status))
        {
-               OurPort = ObCreateObject (
-                               ServerPortHandle,
-                               PORT_ALL_ACCESS,
-                               NULL,
-                               ExPortType
-                               );
-               NiInitializePort(OurPort);
+         return(Status);
        }
-       /*
-        * Dequeue the connection request
-        */
-       KeAcquireSpinLock (& NamedPort->Lock, & oldIrql);
-       ConnectionRequest = EiDequeueConnectMessagePort (NamedPort);
-       KeReleaseSpinLock (& NamedPort->Lock, oldIrql);
-
-       if (AcceptIt != 1)
-       {       
-               EiReplyOrRequestPort (
-                       ConnectionRequest->Sender, 
-                       LpcMessage, 
-                       LPC_CONNECTION_REFUSED,
-                       NamedPort
-                       );
-               KeSetEvent (
-                       & ConnectionRequest->Sender->Event,
-                       IO_NO_INCREMENT,
-                       FALSE
-                       );
-               ObDereferenceObject (ConnectionRequest->Sender);
-               ExFreePool (ConnectionRequest); 
-               ObDereferenceObject (NamedPort);
-               return (STATUS_SUCCESS);
+
+      ObDereferenceObject(SectionObject);
+    }
+  if (ReadMap != NULL && CRequest->SendSectionObject != NULL)
+    {
+      LARGE_INTEGER SectionOffset;
+
+      SectionOffset = CRequest->SendSectionOffset;
+      ReadMap->ViewSize = CRequest->SendViewSize;
+      ReadMap->ViewBase = 0;
+      Status = MmMapViewOfSection(CRequest->SendSectionObject,
+                                 PsGetCurrentProcess(),
+                                 &ReadMap->ViewBase,
+                                 0,
+                                 CRequest->SendViewSize,
+                                 &SectionOffset,
+                                 &CRequest->SendViewSize,
+                                 ViewUnmap,
+                                 0 /* MEM_TOP_DOWN? */,
+                                 PAGE_READWRITE);
+      if (!NT_SUCCESS(Status))
+       {
+         return(Status);
        }
-       /*
-        * Connect the two ports
-        */
-       OurPort->OtherPort = ConnectionRequest->Sender;
-       OurPort->OtherPort->OtherPort = OurPort;
-       EiReplyOrRequestPort (
-               ConnectionRequest->Sender, 
-               LpcMessage, 
-               LPC_REPLY,
-               OurPort
-               );
-       ExFreePool (ConnectionRequest);
-   
-       ObDereferenceObject (OurPort);   
-       ObDereferenceObject (NamedPort);
-    
-       return (STATUS_SUCCESS);
+    }
+
+  /*
+   * Finish the reply.
+   */
+  if (ReadMap != NULL)
+    {
+      CReply->SendServerViewBase = ReadMap->ViewBase;
+    }
+  else
+    {
+      CReply->SendServerViewBase = 0;
+    }
+  if (WriteMap != NULL)
+    {
+      CReply->ReceiveClientViewBase = WriteMap->ViewRemoteBase;
+    }
+  CReply->MaximumMessageSize = LPC_MAX_MESSAGE_LENGTH;
+
+
+  /*
+   * Connect the two ports
+   */
+  OurPort->OtherPort = ConnectionRequest->Sender;
+  OurPort->OtherPort->OtherPort = OurPort;
+  EiReplyOrRequestPort(ConnectionRequest->Sender,
+                      (PPORT_MESSAGE)CReply,
+                      LPC_REPLY,
+                      OurPort);
+  ExFreePool(ConnectionRequest);
+  ExFreePool(CReply);
+
+  ObDereferenceObject(OurPort);
+  ObDereferenceObject(NamedPort);
+
+  return (STATUS_SUCCESS);
 }
 
+/**********************************************************************
+ * NAME                                                        EXPORTED
+ *     NtSecureConnectPort/9
+ *
+ * DESCRIPTION
+ *     Connect to a named port and wait for the other side to
+ *     accept the connection. Possibly verify that the server
+ *     matches the ServerSid (trusted server).
+ *     Present in w2k+.
+ *
+ * ARGUMENTS
+ *     ConnectedPort
+ *     PortName: fully qualified name in the Ob name space;
+ *     Qos
+ *     WriteMap
+ *     ServerSid
+ *     ReadMap
+ *     MaxMessageSize
+ *     ConnectInfo
+ *     UserConnectInfoLength
+ *
+ * RETURN VALUE
+ */
+NTSTATUS STDCALL
+NtSecureConnectPort (OUT    PHANDLE                            ConnectedPort,
+                    IN     PUNICODE_STRING                     PortName,
+                    IN     PSECURITY_QUALITY_OF_SERVICE        Qos,
+                    IN OUT PPORT_VIEW                  WriteMap                OPTIONAL,
+                    IN     PSID                                ServerSid               OPTIONAL,
+                    IN OUT PREMOTE_PORT_VIEW                   ReadMap                 OPTIONAL,
+                    OUT    PULONG                              MaxMessageSize          OPTIONAL,
+                    IN OUT PVOID                               ConnectInfo             OPTIONAL,
+                    IN OUT PULONG                              UserConnectInfoLength   OPTIONAL)
+{
+  /* TODO: implement a new object type: WaitablePort */
+  /* TODO: verify the process' SID that hosts the rendez-vous port equals ServerSid */
+  return NtConnectPort (ConnectedPort,
+                       PortName,
+                       Qos,
+                       WriteMap,
+                       ReadMap,
+                       MaxMessageSize,
+                       ConnectInfo,
+                       UserConnectInfoLength);
+}
 
 /* EOF */