1 /* $Id: connect.c,v 1.27 2004/08/15 16:39:06 chorns Exp $
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/lpc/connect.c
6 * PURPOSE: Communication mechanism
7 * PROGRAMMER: David Welch (welch@cwcom.net)
12 /* INCLUDES *****************************************************************/
16 #include <internal/debug.h>
18 /* GLOBALS *******************************************************************/
20 #define TAG_LPC_CONNECT_MESSAGE TAG('L', 'P', 'C', 'C')
22 /* FUNCTIONS *****************************************************************/
24 /**********************************************************************
35 EiConnectPort(IN PEPORT
* ConnectedPort
,
37 IN PSECTION_OBJECT Section
,
38 IN LARGE_INTEGER SectionOffset
,
40 OUT PVOID
* ClientSendViewBase
,
41 OUT PVOID
* ServerSendViewBase
,
42 OUT PULONG ReceiveViewSize
,
43 OUT PVOID
* ReceiveViewBase
,
44 OUT PULONG MaximumMessageSize
,
45 IN OUT PVOID ConnectData
,
46 IN OUT PULONG ConnectDataLength
)
48 PEPORT_CONNECT_REQUEST_MESSAGE RequestMessage
;
49 ULONG RequestConnectDataLength
;
52 PEPORT_CONNECT_REPLY_MESSAGE CReply
;
56 if (ConnectDataLength
== NULL
)
58 RequestConnectDataLength
= 0;
62 RequestConnectDataLength
= *ConnectDataLength
;
66 * Create a port to represent our side of the connection
68 Status
= ObCreateObject (KernelMode
,
77 if (!NT_SUCCESS(Status
))
81 NiInitializePort(OurPort
, EPORT_TYPE_CLIENT_COMM_PORT
, NamedPort
);
84 * Allocate a request message.
86 RequestMessage
= ExAllocatePool(NonPagedPool
,
87 sizeof(EPORT_CONNECT_REQUEST_MESSAGE
) +
88 RequestConnectDataLength
);
89 if (RequestMessage
== NULL
)
91 ObDereferenceObject(OurPort
);
92 return(STATUS_NO_MEMORY
);
96 * Initialize the request message.
98 RequestMessage
->MessageHeader
.DataSize
=
99 sizeof(EPORT_CONNECT_REQUEST_MESSAGE
) + RequestConnectDataLength
-
101 RequestMessage
->MessageHeader
.MessageSize
=
102 sizeof(EPORT_CONNECT_REQUEST_MESSAGE
) + RequestConnectDataLength
;
103 DPRINT("RequestMessageSize %d\n",
104 RequestMessage
->MessageHeader
.MessageSize
);
105 RequestMessage
->MessageHeader
.SectionSize
= 0;
106 RequestMessage
->ConnectingProcess
= PsGetCurrentProcess();
107 ObReferenceObjectByPointer(RequestMessage
->ConnectingProcess
,
108 PROCESS_VM_OPERATION
,
111 RequestMessage
->SendSectionObject
= (struct _SECTION_OBJECT
*)Section
;
112 RequestMessage
->SendSectionOffset
= SectionOffset
;
113 RequestMessage
->SendViewSize
= ViewSize
;
114 RequestMessage
->ConnectDataLength
= RequestConnectDataLength
;
115 if (RequestConnectDataLength
> 0)
117 memcpy(RequestMessage
->ConnectData
, ConnectData
,
118 RequestConnectDataLength
);
122 * Queue the message to the named port
124 EiReplyOrRequestPort(NamedPort
,
125 &RequestMessage
->MessageHeader
,
126 LPC_CONNECTION_REQUEST
,
128 KeReleaseSemaphore(&NamedPort
->Semaphore
, IO_NO_INCREMENT
, 1, FALSE
);
129 ExFreePool(RequestMessage
);
132 * Wait for them to accept our connection
134 KeWaitForSingleObject(&OurPort
->Semaphore
,
141 * Dequeue the response
143 KeAcquireSpinLock (&OurPort
->Lock
, &oldIrql
);
144 Reply
= EiDequeueMessagePort (OurPort
);
145 KeReleaseSpinLock (&OurPort
->Lock
, oldIrql
);
146 CReply
= (PEPORT_CONNECT_REPLY_MESSAGE
)&Reply
->Message
;
149 * Do some initial cleanup.
151 ObDereferenceObject(PsGetCurrentProcess());
154 * Check for connection refusal.
156 if (CReply
->MessageHeader
.MessageType
== LPC_CONNECTION_REFUSED
)
158 ObDereferenceObject(OurPort
);
161 * FIXME: Check what NT does here. Giving the user data back on
162 * connect failure sounds reasonable; it probably wouldn't break
165 if (ConnectDataLength
!= NULL
)
167 *ConnectDataLength
= CReply
->ConnectDataLength
;
168 memcpy(ConnectData
, CReply
->ConnectData
, CReply
->ConnectDataLength
);
170 return(STATUS_PORT_CONNECTION_REFUSED
);
174 * Otherwise we are connected. Copy data back to the client.
176 *ServerSendViewBase
= CReply
->SendServerViewBase
;
177 *ReceiveViewSize
= CReply
->ReceiveClientViewSize
;
178 *ReceiveViewBase
= CReply
->ReceiveClientViewBase
;
179 *MaximumMessageSize
= CReply
->MaximumMessageSize
;
180 if (ConnectDataLength
!= NULL
)
182 *ConnectDataLength
= CReply
->ConnectDataLength
;
183 memcpy(ConnectData
, CReply
->ConnectData
, CReply
->ConnectDataLength
);
187 * Create our view of the send section object.
191 *ClientSendViewBase
= 0;
192 Status
= MmMapViewOfSection(Section
,
193 PsGetCurrentProcess(),
200 0 /* MEM_TOP_DOWN? */,
202 if (!NT_SUCCESS(Status
))
204 /* FIXME: Cleanup here. */
210 * Do the final initialization of our port.
212 OurPort
->State
= EPORT_CONNECTED_CLIENT
;
218 *ConnectedPort
= OurPort
;
219 return(STATUS_SUCCESS
);
222 /**********************************************************************
227 * Connect to a named port and wait for the other side to
228 * accept or reject the connection request.
238 * UserConnectInfoLength
245 NtConnectPort (PHANDLE UnsafeConnectedPortHandle
,
246 PUNICODE_STRING PortName
,
247 PSECURITY_QUALITY_OF_SERVICE Qos
,
248 PLPC_SECTION_WRITE UnsafeWriteMap
,
249 PLPC_SECTION_READ UnsafeReadMap
,
250 PULONG UnsafeMaximumMessageSize
,
251 PVOID UnsafeConnectData
,
252 PULONG UnsafeConnectDataLength
)
254 HANDLE ConnectedPortHandle
;
255 LPC_SECTION_WRITE WriteMap
;
256 LPC_SECTION_READ ReadMap
;
257 ULONG MaximumMessageSize
;
259 ULONG ConnectDataLength
;
260 PSECTION_OBJECT SectionObject
;
261 LARGE_INTEGER SectionOffset
;
262 PEPORT ConnectedPort
;
267 * Copy in write map and partially validate.
269 if (UnsafeWriteMap
!= NULL
)
271 Status
= MmCopyFromCaller(&WriteMap
,
273 sizeof(LPC_SECTION_WRITE
));
274 if (!NT_SUCCESS(Status
))
278 if (WriteMap
.Length
!= sizeof(LPC_SECTION_WRITE
))
280 return(STATUS_INVALID_PARAMETER_4
);
282 SectionOffset
.QuadPart
= WriteMap
.SectionOffset
;
286 WriteMap
.SectionHandle
= INVALID_HANDLE_VALUE
;
290 * Handle connection data.
292 if (UnsafeConnectData
== NULL
)
294 ConnectDataLength
= 0;
299 if (ExGetPreviousMode() == KernelMode
)
301 ConnectDataLength
= *UnsafeConnectDataLength
;
302 ConnectData
= UnsafeConnectData
;
306 Status
= MmCopyFromCaller(&ConnectDataLength
,
307 UnsafeConnectDataLength
,
309 if (!NT_SUCCESS(Status
))
313 ConnectData
= ExAllocatePool(NonPagedPool
, ConnectDataLength
);
314 if (ConnectData
== NULL
&& ConnectDataLength
!= 0)
316 return(STATUS_NO_MEMORY
);
318 Status
= MmCopyFromCaller(ConnectData
,
321 if (!NT_SUCCESS(Status
))
323 ExFreePool(ConnectData
);
330 * Reference the named port.
332 Status
= ObReferenceObjectByName (PortName
,
335 PORT_ALL_ACCESS
, /* DesiredAccess */
340 if (!NT_SUCCESS(Status
))
342 if (KeGetPreviousMode() != KernelMode
)
344 ExFreePool(ConnectData
);
350 * Reference the send section object.
352 if (WriteMap
.SectionHandle
!= INVALID_HANDLE_VALUE
)
354 Status
= ObReferenceObjectByHandle(WriteMap
.SectionHandle
,
355 SECTION_MAP_READ
| SECTION_MAP_WRITE
,
358 (PVOID
*)&SectionObject
,
360 if (!NT_SUCCESS(Status
))
362 ObDereferenceObject(NamedPort
);
363 if (KeGetPreviousMode() != KernelMode
)
365 ExFreePool(ConnectData
);
372 SectionObject
= NULL
;
376 * Do the connection establishment.
378 Status
= EiConnectPort(&ConnectedPort
,
384 &WriteMap
.TargetViewBase
,
390 if (!NT_SUCCESS(Status
))
392 /* FIXME: Again, check what NT does here. */
393 if (UnsafeConnectDataLength
!= NULL
)
395 if (ExGetPreviousMode() != KernelMode
)
397 MmCopyToCaller(UnsafeConnectData
,
400 ExFreePool(ConnectData
);
402 MmCopyToCaller(UnsafeConnectDataLength
,
410 * Do some initial cleanup.
412 if (SectionObject
!= NULL
)
414 ObDereferenceObject(SectionObject
);
415 SectionObject
= NULL
;
417 ObDereferenceObject(NamedPort
);
421 * Copy the data back to the caller.
423 if (ExGetPreviousMode() != KernelMode
)
425 if (UnsafeConnectDataLength
!= NULL
)
427 Status
= MmCopyToCaller(UnsafeConnectDataLength
,
430 if (!NT_SUCCESS(Status
))
435 if (UnsafeConnectData
!= NULL
&& ConnectData
!= NULL
)
437 Status
= MmCopyToCaller(UnsafeConnectData
,
440 ExFreePool(ConnectData
);
441 if (!NT_SUCCESS(Status
))
447 Status
= ObInsertObject(ConnectedPort
,
452 &ConnectedPortHandle
);
453 if (!NT_SUCCESS(Status
))
457 Status
= MmCopyToCaller(UnsafeConnectedPortHandle
,
458 &ConnectedPortHandle
,
460 if (!NT_SUCCESS(Status
))
464 if (UnsafeWriteMap
!= NULL
)
466 Status
= MmCopyToCaller(UnsafeWriteMap
,
468 sizeof(LPC_SECTION_WRITE
));
469 if (!NT_SUCCESS(Status
))
474 if (UnsafeReadMap
!= NULL
)
476 Status
= MmCopyToCaller(UnsafeReadMap
,
478 sizeof(LPC_SECTION_READ
));
479 if (!NT_SUCCESS(Status
))
484 if (UnsafeMaximumMessageSize
!= NULL
)
486 Status
= MmCopyToCaller(UnsafeMaximumMessageSize
,
489 if (!NT_SUCCESS(Status
))
499 return(STATUS_SUCCESS
);
503 /**********************************************************************
505 * NtAcceptConnectPort/6
519 /*EXPORTED*/ NTSTATUS STDCALL
520 NtAcceptConnectPort (PHANDLE ServerPortHandle
,
521 HANDLE NamedPortHandle
,
522 PLPC_MESSAGE LpcMessage
,
524 PLPC_SECTION_WRITE WriteMap
,
525 PLPC_SECTION_READ ReadMap
)
529 PEPORT OurPort
= NULL
;
530 PQUEUEDMESSAGE ConnectionRequest
;
532 PEPORT_CONNECT_REQUEST_MESSAGE CRequest
;
533 PEPORT_CONNECT_REPLY_MESSAGE CReply
;
536 Size
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
);
539 Size
+= LpcMessage
->DataSize
;
542 CReply
= ExAllocatePool(NonPagedPool
, Size
);
545 return(STATUS_NO_MEMORY
);
548 Status
= ObReferenceObjectByHandle(NamedPortHandle
,
554 if (!NT_SUCCESS(Status
))
561 * Create a port object for our side of the connection
565 Status
= ObCreateObject(ExGetPreviousMode(),
574 if (!NT_SUCCESS(Status
))
577 ObDereferenceObject(NamedPort
);
581 Status
= ObInsertObject ((PVOID
)OurPort
,
587 if (!NT_SUCCESS(Status
))
589 ObDereferenceObject(OurPort
);
591 ObDereferenceObject(NamedPort
);
595 NiInitializePort(OurPort
, EPORT_TYPE_SERVER_COMM_PORT
, NamedPort
);
599 * Dequeue the connection request
601 KeAcquireSpinLock(&NamedPort
->Lock
, &oldIrql
);
602 ConnectionRequest
= EiDequeueConnectMessagePort (NamedPort
);
603 KeReleaseSpinLock(&NamedPort
->Lock
, oldIrql
);
604 CRequest
= (PEPORT_CONNECT_REQUEST_MESSAGE
)(&ConnectionRequest
->Message
);
609 if (LpcMessage
!= NULL
)
611 memcpy(&CReply
->MessageHeader
, LpcMessage
, sizeof(LPC_MESSAGE
));
612 memcpy(&CReply
->ConnectData
, (PVOID
)(LpcMessage
+ 1),
613 LpcMessage
->DataSize
);
614 CReply
->MessageHeader
.MessageSize
=
615 sizeof(EPORT_CONNECT_REPLY_MESSAGE
) + LpcMessage
->DataSize
;
616 CReply
->MessageHeader
.DataSize
= CReply
->MessageHeader
.MessageSize
-
618 CReply
->ConnectDataLength
= LpcMessage
->DataSize
;
622 CReply
->MessageHeader
.MessageSize
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
);
623 CReply
->MessageHeader
.DataSize
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
) -
625 CReply
->ConnectDataLength
= 0;
629 EiReplyOrRequestPort(ConnectionRequest
->Sender
,
630 &CReply
->MessageHeader
,
631 LPC_CONNECTION_REFUSED
,
633 KeReleaseSemaphore(&ConnectionRequest
->Sender
->Semaphore
,
637 ObDereferenceObject(ConnectionRequest
->Sender
);
638 ExFreePool(ConnectionRequest
);
640 ObDereferenceObject(NamedPort
);
641 return (STATUS_SUCCESS
);
645 * Prepare the connection.
647 if (WriteMap
!= NULL
)
649 PSECTION_OBJECT SectionObject
;
650 LARGE_INTEGER SectionOffset
;
652 Status
= ObReferenceObjectByHandle(WriteMap
->SectionHandle
,
653 SECTION_MAP_READ
| SECTION_MAP_WRITE
,
656 (PVOID
*)&SectionObject
,
658 if (!NT_SUCCESS(Status
))
663 SectionOffset
.QuadPart
= WriteMap
->SectionOffset
;
664 WriteMap
->TargetViewBase
= 0;
665 CReply
->ReceiveClientViewSize
= WriteMap
->ViewSize
;
666 Status
= MmMapViewOfSection(SectionObject
,
667 CRequest
->ConnectingProcess
,
668 &WriteMap
->TargetViewBase
,
670 CReply
->ReceiveClientViewSize
,
672 &CReply
->ReceiveClientViewSize
,
674 0 /* MEM_TOP_DOWN? */,
676 if (!NT_SUCCESS(Status
))
681 WriteMap
->ViewBase
= 0;
682 Status
= MmMapViewOfSection(SectionObject
,
683 PsGetCurrentProcess(),
690 0 /* MEM_TOP_DOWN? */,
692 if (!NT_SUCCESS(Status
))
697 ObDereferenceObject(SectionObject
);
699 if (ReadMap
!= NULL
&& CRequest
->SendSectionObject
!= NULL
)
701 LARGE_INTEGER SectionOffset
;
703 SectionOffset
= CRequest
->SendSectionOffset
;
704 ReadMap
->ViewSize
= CRequest
->SendViewSize
;
705 ReadMap
->ViewBase
= 0;
706 Status
= MmMapViewOfSection(CRequest
->SendSectionObject
,
707 PsGetCurrentProcess(),
710 CRequest
->SendViewSize
,
712 &CRequest
->SendViewSize
,
714 0 /* MEM_TOP_DOWN? */,
716 if (!NT_SUCCESS(Status
))
727 CReply
->SendServerViewBase
= ReadMap
->ViewBase
;
731 CReply
->SendServerViewBase
= 0;
733 if (WriteMap
!= NULL
)
735 CReply
->ReceiveClientViewBase
= WriteMap
->TargetViewBase
;
737 CReply
->MaximumMessageSize
= PORT_MAX_MESSAGE_LENGTH
;
741 * Connect the two ports
743 OurPort
->OtherPort
= ConnectionRequest
->Sender
;
744 OurPort
->OtherPort
->OtherPort
= OurPort
;
745 EiReplyOrRequestPort(ConnectionRequest
->Sender
,
746 (PLPC_MESSAGE
)CReply
,
749 ExFreePool(ConnectionRequest
);
752 ObDereferenceObject(OurPort
);
753 ObDereferenceObject(NamedPort
);
755 return (STATUS_SUCCESS
);
758 /**********************************************************************
760 * NtSecureConnectPort/9
763 * Connect to a named port and wait for the other side to
764 * accept the connection. Possibly verify that the server
765 * matches the ServerSid (trusted server).
770 * PortName: fully qualified name in the Ob name space;
777 * UserConnectInfoLength
782 NtSecureConnectPort (OUT PHANDLE ConnectedPort
,
783 IN PUNICODE_STRING PortName
,
784 IN PSECURITY_QUALITY_OF_SERVICE Qos
,
785 IN OUT PLPC_SECTION_WRITE WriteMap OPTIONAL
,
786 IN PSID ServerSid OPTIONAL
,
787 IN OUT PLPC_SECTION_READ ReadMap OPTIONAL
,
788 OUT PULONG MaxMessageSize OPTIONAL
,
789 IN OUT PVOID ConnectInfo OPTIONAL
,
790 IN OUT PULONG UserConnectInfoLength OPTIONAL
)
792 /* TODO: implement a new object type: WaitablePort */
793 /* TODO: verify the process' SID that hosts the rendez-vous port equals ServerSid */
794 return NtConnectPort (ConnectedPort
,
801 UserConnectInfoLength
);