1 /* $Id: connect.c,v 1.22 2003/12/30 18:52:05 fireball 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 *****************************************************************/
14 #define NTOS_MODE_KERNEL
16 #include <internal/ob.h>
17 #include <internal/port.h>
18 #include <internal/dbg.h>
19 #include <internal/pool.h>
20 #include <internal/safe.h>
21 #include <internal/mm.h>
24 #include <internal/debug.h>
26 /* GLOBALS *******************************************************************/
28 #define TAG_LPC_CONNECT_MESSAGE TAG('L', 'P', 'C', 'C')
30 /* FUNCTIONS *****************************************************************/
33 EiConnectPort(IN PEPORT
* ConnectedPort
,
35 IN PSECTION_OBJECT Section
,
36 IN LARGE_INTEGER SectionOffset
,
38 OUT PVOID
* ClientSendViewBase
,
39 OUT PVOID
* ServerSendViewBase
,
40 OUT PULONG ReceiveViewSize
,
41 OUT PVOID
* ReceiveViewBase
,
42 OUT PULONG MaximumMessageSize
,
43 IN OUT PVOID ConnectData
,
44 IN OUT PULONG ConnectDataLength
)
46 PEPORT_CONNECT_REQUEST_MESSAGE RequestMessage
;
47 ULONG RequestConnectDataLength
;
50 PEPORT_CONNECT_REPLY_MESSAGE CReply
;
54 if (ConnectDataLength
== NULL
)
56 RequestConnectDataLength
= 0;
60 RequestConnectDataLength
= *ConnectDataLength
;
64 * Create a port to represent our side of the connection
66 Status
= ObCreateObject (KernelMode
,
75 if (!NT_SUCCESS(Status
))
79 NiInitializePort(OurPort
);
82 * Allocate a request message.
84 RequestMessage
= ExAllocatePool(NonPagedPool
,
85 sizeof(EPORT_CONNECT_REQUEST_MESSAGE
) +
86 RequestConnectDataLength
);
87 if (RequestMessage
== NULL
)
89 ObDereferenceObject(OurPort
);
90 return(STATUS_NO_MEMORY
);
94 * Initialize the request message.
96 RequestMessage
->MessageHeader
.DataSize
=
97 sizeof(EPORT_CONNECT_REQUEST_MESSAGE
) + RequestConnectDataLength
-
99 RequestMessage
->MessageHeader
.MessageSize
=
100 sizeof(EPORT_CONNECT_REQUEST_MESSAGE
) + RequestConnectDataLength
;
101 DPRINT("RequestMessageSize %d\n",
102 RequestMessage
->MessageHeader
.MessageSize
);
103 RequestMessage
->MessageHeader
.SectionSize
= 0;
104 RequestMessage
->ConnectingProcess
= PsGetCurrentProcess();
105 ObReferenceObjectByPointer(RequestMessage
->ConnectingProcess
,
106 PROCESS_VM_OPERATION
,
109 RequestMessage
->SendSectionObject
= (struct _SECTION_OBJECT
*)Section
;
110 RequestMessage
->SendSectionOffset
= SectionOffset
;
111 RequestMessage
->SendViewSize
= ViewSize
;
112 RequestMessage
->ConnectDataLength
= RequestConnectDataLength
;
113 if (RequestConnectDataLength
> 0)
115 memcpy(RequestMessage
->ConnectData
, ConnectData
,
116 RequestConnectDataLength
);
120 * Queue the message to the named port
122 EiReplyOrRequestPort(NamedPort
,
123 &RequestMessage
->MessageHeader
,
124 LPC_CONNECTION_REQUEST
,
126 KeReleaseSemaphore(&NamedPort
->Semaphore
, IO_NO_INCREMENT
, 1, FALSE
);
127 ExFreePool(RequestMessage
);
130 * Wait for them to accept our connection
132 KeWaitForSingleObject(&OurPort
->Semaphore
,
139 * Dequeue the response
141 KeAcquireSpinLock (&OurPort
->Lock
, &oldIrql
);
142 Reply
= EiDequeueMessagePort (OurPort
);
143 KeReleaseSpinLock (&OurPort
->Lock
, oldIrql
);
144 CReply
= (PEPORT_CONNECT_REPLY_MESSAGE
)&Reply
->Message
;
147 * Do some initial cleanup.
149 ObDereferenceObject(PsGetCurrentProcess());
152 * Check for connection refusal.
154 if (CReply
->MessageHeader
.MessageType
== LPC_CONNECTION_REFUSED
)
156 ObDereferenceObject(OurPort
);
159 * FIXME: Check what NT does here. Giving the user data back on
160 * connect failure sounds reasonable; it probably wouldn't break
163 if (ConnectDataLength
!= NULL
)
165 *ConnectDataLength
= CReply
->ConnectDataLength
;
166 memcpy(ConnectData
, CReply
->ConnectData
, CReply
->ConnectDataLength
);
168 return(STATUS_PORT_CONNECTION_REFUSED
);
172 * Otherwise we are connected. Copy data back to the client.
174 *ServerSendViewBase
= CReply
->SendServerViewBase
;
175 *ReceiveViewSize
= CReply
->ReceiveClientViewSize
;
176 *ReceiveViewBase
= CReply
->ReceiveClientViewBase
;
177 *MaximumMessageSize
= CReply
->MaximumMessageSize
;
178 if (ConnectDataLength
!= NULL
)
180 *ConnectDataLength
= CReply
->ConnectDataLength
;
181 memcpy(ConnectData
, CReply
->ConnectData
, CReply
->ConnectDataLength
);
185 * Create our view of the send section object.
189 *ClientSendViewBase
= 0;
190 Status
= MmMapViewOfSection(Section
,
191 PsGetCurrentProcess(),
198 0 /* MEM_TOP_DOWN? */,
200 if (!NT_SUCCESS(Status
))
202 /* FIXME: Cleanup here. */
208 * Do the final initialization of our port.
210 OurPort
->State
= EPORT_CONNECTED_CLIENT
;
216 *ConnectedPort
= OurPort
;
217 return(STATUS_SUCCESS
);
220 /**********************************************************************
225 * Connect to a named port and wait for the other side to
226 * accept the connection.
236 * UserConnectInfoLength
243 NtConnectPort (PHANDLE UnsafeConnectedPortHandle
,
244 PUNICODE_STRING PortName
,
245 PSECURITY_QUALITY_OF_SERVICE Qos
,
246 PLPC_SECTION_WRITE UnsafeWriteMap
,
247 PLPC_SECTION_READ UnsafeReadMap
,
248 PULONG UnsafeMaximumMessageSize
,
249 PVOID UnsafeConnectData
,
250 PULONG UnsafeConnectDataLength
)
252 HANDLE ConnectedPortHandle
;
253 LPC_SECTION_WRITE WriteMap
;
254 LPC_SECTION_READ ReadMap
;
255 ULONG MaximumMessageSize
;
257 ULONG ConnectDataLength
;
258 PSECTION_OBJECT SectionObject
;
259 LARGE_INTEGER SectionOffset
;
260 PEPORT ConnectedPort
;
265 * Copy in write map and partially validate.
267 if (UnsafeWriteMap
!= NULL
)
269 Status
= MmCopyFromCaller(&WriteMap
,
271 sizeof(LPC_SECTION_WRITE
));
272 if (!NT_SUCCESS(Status
))
276 if (WriteMap
.Length
!= sizeof(LPC_SECTION_WRITE
))
278 return(STATUS_INVALID_PARAMETER_4
);
280 SectionOffset
.QuadPart
= WriteMap
.SectionOffset
;
284 WriteMap
.SectionHandle
= INVALID_HANDLE_VALUE
;
288 * Handle connection data.
290 if (UnsafeConnectData
== NULL
)
292 ConnectDataLength
= 0;
297 if (ExGetPreviousMode() == KernelMode
)
299 ConnectDataLength
= *UnsafeConnectDataLength
;
300 ConnectData
= UnsafeConnectData
;
304 Status
= MmCopyFromCaller(&ConnectDataLength
,
305 UnsafeConnectDataLength
,
307 if (!NT_SUCCESS(Status
))
311 ConnectData
= ExAllocatePool(NonPagedPool
, ConnectDataLength
);
312 if (ConnectData
== NULL
&& ConnectDataLength
!= 0)
314 return(STATUS_NO_MEMORY
);
316 Status
= MmCopyFromCaller(ConnectData
,
319 if (!NT_SUCCESS(Status
))
321 ExFreePool(ConnectData
);
328 * Reference the named port.
330 Status
= ObReferenceObjectByName (PortName
,
333 PORT_ALL_ACCESS
, /* DesiredAccess */
338 if (!NT_SUCCESS(Status
))
340 if (KeGetPreviousMode() != KernelMode
)
342 ExFreePool(ConnectData
);
348 * Reference the send section object.
350 if (WriteMap
.SectionHandle
!= INVALID_HANDLE_VALUE
)
352 Status
= ObReferenceObjectByHandle(WriteMap
.SectionHandle
,
353 SECTION_MAP_READ
| SECTION_MAP_WRITE
,
356 (PVOID
*)&SectionObject
,
358 if (!NT_SUCCESS(Status
))
360 ObDereferenceObject(NamedPort
);
361 if (KeGetPreviousMode() != KernelMode
)
363 ExFreePool(ConnectData
);
370 SectionObject
= NULL
;
374 * Do the connection establishment.
376 Status
= EiConnectPort(&ConnectedPort
,
382 &WriteMap
.TargetViewBase
,
388 if (!NT_SUCCESS(Status
))
390 /* FIXME: Again, check what NT does here. */
391 if (UnsafeConnectDataLength
!= NULL
)
393 if (ExGetPreviousMode() != KernelMode
)
395 MmCopyToCaller(UnsafeConnectData
,
398 ExFreePool(ConnectData
);
400 MmCopyToCaller(UnsafeConnectDataLength
,
408 * Do some initial cleanup.
410 if (SectionObject
!= NULL
)
412 ObDereferenceObject(SectionObject
);
413 SectionObject
= NULL
;
415 ObDereferenceObject(NamedPort
);
419 * Copy the data back to the caller.
421 if (ExGetPreviousMode() != KernelMode
)
423 if (UnsafeConnectDataLength
!= NULL
)
425 if (ExGetPreviousMode() != KernelMode
)
427 Status
= MmCopyToCaller(UnsafeConnectData
,
430 ExFreePool(ConnectData
);
431 if (!NT_SUCCESS(Status
))
436 Status
= MmCopyToCaller(UnsafeConnectDataLength
,
439 if (!NT_SUCCESS(Status
))
445 Status
= ObInsertObject(ConnectedPort
,
450 &ConnectedPortHandle
);
451 if (!NT_SUCCESS(Status
))
455 Status
= MmCopyToCaller(UnsafeConnectedPortHandle
,
456 &ConnectedPortHandle
,
458 if (!NT_SUCCESS(Status
))
462 if (UnsafeWriteMap
!= NULL
)
464 Status
= MmCopyToCaller(UnsafeWriteMap
,
466 sizeof(LPC_SECTION_WRITE
));
467 if (!NT_SUCCESS(Status
))
472 if (UnsafeReadMap
!= NULL
)
474 Status
= MmCopyToCaller(UnsafeReadMap
,
476 sizeof(LPC_SECTION_READ
));
477 if (!NT_SUCCESS(Status
))
482 if (UnsafeMaximumMessageSize
!= NULL
)
484 Status
= MmCopyToCaller(UnsafeMaximumMessageSize
,
487 if (!NT_SUCCESS(Status
))
497 return(STATUS_SUCCESS
);
501 /**********************************************************************
503 * NtAcceptConnectPort@24
517 /*EXPORTED*/ NTSTATUS STDCALL
518 NtAcceptConnectPort (PHANDLE ServerPortHandle
,
519 HANDLE NamedPortHandle
,
520 PLPC_MESSAGE LpcMessage
,
522 PLPC_SECTION_WRITE WriteMap
,
523 PLPC_SECTION_READ ReadMap
)
527 PEPORT OurPort
= NULL
;
528 PQUEUEDMESSAGE ConnectionRequest
;
530 PEPORT_CONNECT_REQUEST_MESSAGE CRequest
;
531 PEPORT_CONNECT_REPLY_MESSAGE CReply
;
534 Size
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
);
537 Size
+= LpcMessage
->DataSize
;
540 CReply
= ExAllocatePool(NonPagedPool
, Size
);
543 return(STATUS_NO_MEMORY
);
546 Status
= ObReferenceObjectByHandle(NamedPortHandle
,
552 if (!NT_SUCCESS(Status
))
559 * Create a port object for our side of the connection
563 Status
= ObCreateObject(ExGetPreviousMode(),
572 if (!NT_SUCCESS(Status
))
575 ObDereferenceObject(NamedPort
);
579 Status
= ObInsertObject ((PVOID
)OurPort
,
585 if (!NT_SUCCESS(Status
))
587 ObDereferenceObject(OurPort
);
589 ObDereferenceObject(NamedPort
);
593 NiInitializePort(OurPort
);
597 * Dequeue the connection request
599 KeAcquireSpinLock(&NamedPort
->Lock
, &oldIrql
);
600 ConnectionRequest
= EiDequeueConnectMessagePort (NamedPort
);
601 KeReleaseSpinLock(&NamedPort
->Lock
, oldIrql
);
602 CRequest
= (PEPORT_CONNECT_REQUEST_MESSAGE
)(&ConnectionRequest
->Message
);
607 if (LpcMessage
!= NULL
)
609 memcpy(&CReply
->MessageHeader
, LpcMessage
, sizeof(LPC_MESSAGE
));
610 memcpy(&CReply
->ConnectData
, (PVOID
)(LpcMessage
+ 1),
611 LpcMessage
->DataSize
);
612 CReply
->MessageHeader
.MessageSize
=
613 sizeof(EPORT_CONNECT_REPLY_MESSAGE
) + LpcMessage
->DataSize
;
614 CReply
->MessageHeader
.DataSize
= CReply
->MessageHeader
.MessageSize
-
616 CReply
->ConnectDataLength
= LpcMessage
->DataSize
;
620 CReply
->MessageHeader
.MessageSize
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
);
621 CReply
->MessageHeader
.DataSize
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
) -
623 CReply
->ConnectDataLength
= 0;
627 EiReplyOrRequestPort(ConnectionRequest
->Sender
,
628 &CReply
->MessageHeader
,
629 LPC_CONNECTION_REFUSED
,
631 KeReleaseSemaphore(&ConnectionRequest
->Sender
->Semaphore
,
635 ObDereferenceObject(ConnectionRequest
->Sender
);
636 ExFreePool(ConnectionRequest
);
638 ObDereferenceObject(NamedPort
);
639 return (STATUS_SUCCESS
);
643 * Prepare the connection.
645 if (WriteMap
!= NULL
)
647 PSECTION_OBJECT SectionObject
;
648 LARGE_INTEGER SectionOffset
;
650 Status
= ObReferenceObjectByHandle(WriteMap
->SectionHandle
,
651 SECTION_MAP_READ
| SECTION_MAP_WRITE
,
654 (PVOID
*)&SectionObject
,
656 if (!NT_SUCCESS(Status
))
661 SectionOffset
.QuadPart
= WriteMap
->SectionOffset
;
662 WriteMap
->TargetViewBase
= 0;
663 CReply
->ReceiveClientViewSize
= WriteMap
->ViewSize
;
664 Status
= MmMapViewOfSection(SectionObject
,
665 CRequest
->ConnectingProcess
,
666 &WriteMap
->TargetViewBase
,
668 CReply
->ReceiveClientViewSize
,
670 &CReply
->ReceiveClientViewSize
,
672 0 /* MEM_TOP_DOWN? */,
674 if (!NT_SUCCESS(Status
))
679 WriteMap
->ViewBase
= 0;
680 Status
= MmMapViewOfSection(SectionObject
,
681 PsGetCurrentProcess(),
688 0 /* MEM_TOP_DOWN? */,
690 if (!NT_SUCCESS(Status
))
695 ObDereferenceObject(SectionObject
);
697 if (ReadMap
!= NULL
&& CRequest
->SendSectionObject
!= NULL
)
699 LARGE_INTEGER SectionOffset
;
701 SectionOffset
= CRequest
->SendSectionOffset
;
702 ReadMap
->ViewSize
= CRequest
->SendViewSize
;
703 ReadMap
->ViewBase
= 0;
704 Status
= MmMapViewOfSection(CRequest
->SendSectionObject
,
705 PsGetCurrentProcess(),
708 CRequest
->SendViewSize
,
710 &CRequest
->SendViewSize
,
712 0 /* MEM_TOP_DOWN? */,
714 if (!NT_SUCCESS(Status
))
725 CReply
->SendServerViewBase
= ReadMap
->ViewBase
;
729 CReply
->SendServerViewBase
= 0;
731 if (WriteMap
!= NULL
)
733 CReply
->ReceiveClientViewBase
= WriteMap
->TargetViewBase
;
735 CReply
->MaximumMessageSize
= 0x148;
739 * Connect the two ports
741 OurPort
->OtherPort
= ConnectionRequest
->Sender
;
742 OurPort
->OtherPort
->OtherPort
= OurPort
;
743 EiReplyOrRequestPort(ConnectionRequest
->Sender
,
744 (PLPC_MESSAGE
)CReply
,
747 ExFreePool(ConnectionRequest
);
750 ObDereferenceObject(OurPort
);
751 ObDereferenceObject(NamedPort
);
753 return (STATUS_SUCCESS
);
756 /**********************************************************************
758 * NtSecureConnectPort@36
761 * Connect to a named port and wait for the other side to
762 * accept the connection. Possibly verify that the server
763 * matches the ServerSid (trusted server).
775 * UserConnectInfoLength
780 NtSecureConnectPort (OUT PHANDLE ConnectedPort
,
781 IN PUNICODE_STRING PortName
,
782 IN PSECURITY_QUALITY_OF_SERVICE Qos
,
783 IN OUT PLPC_SECTION_WRITE WriteMap OPTIONAL
,
784 IN PSID ServerSid OPTIONAL
,
785 IN OUT PLPC_SECTION_READ ReadMap OPTIONAL
,
786 OUT PULONG MaxMessageSize OPTIONAL
,
787 IN OUT PVOID ConnectInfo OPTIONAL
,
788 IN OUT PULONG UserConnectInfoLength OPTIONAL
)
790 return (STATUS_NOT_IMPLEMENTED
);