1 /* $Id: connect.c,v 1.12 2002/09/08 10:23:32 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 *****************************************************************/
14 #include <ddk/ntddk.h>
15 #include <internal/ob.h>
16 #include <internal/port.h>
17 #include <internal/dbg.h>
18 #include <internal/pool.h>
19 #include <internal/safe.h>
20 #include <internal/mm.h>
23 #include <internal/debug.h>
25 /* GLOBALS *******************************************************************/
27 #define TAG_LPC_CONNECT_MESSAGE TAG('L', 'P', 'C', 'C')
29 /* FUNCTIONS *****************************************************************/
32 EiConnectPort(IN PEPORT
* ConnectedPort
,
34 IN PSECTION_OBJECT Section
,
35 IN LARGE_INTEGER SectionOffset
,
37 OUT PVOID
* ClientSendViewBase
,
38 OUT PVOID
* ServerSendViewBase
,
39 OUT PULONG ReceiveViewSize
,
40 OUT PVOID
* ReceiveViewBase
,
41 OUT PULONG MaximumMessageSize
,
42 IN OUT PVOID ConnectData
,
43 IN OUT PULONG ConnectDataLength
)
45 PEPORT_CONNECT_REQUEST_MESSAGE RequestMessage
;
46 ULONG RequestConnectDataLength
;
49 PEPORT_CONNECT_REPLY_MESSAGE CReply
;
53 if (ConnectDataLength
== NULL
)
55 RequestConnectDataLength
= 0;
59 RequestConnectDataLength
= *ConnectDataLength
;
63 * Create a port to represent our side of the connection
65 Status
= ObCreateObject (NULL
,
70 if (!NT_SUCCESS(Status
))
74 NiInitializePort(OurPort
);
77 * Allocate a request message.
79 RequestMessage
= ExAllocatePool(NonPagedPool
,
80 sizeof(EPORT_CONNECT_REQUEST_MESSAGE
) +
81 RequestConnectDataLength
);
82 if (RequestMessage
== NULL
)
84 ObDereferenceObject(OurPort
);
85 return(STATUS_NO_MEMORY
);
89 * Initialize the request message.
91 RequestMessage
->MessageHeader
.DataSize
=
92 sizeof(EPORT_CONNECT_REQUEST_MESSAGE
) + RequestConnectDataLength
-
93 sizeof(LPC_MESSAGE_HEADER
);
94 RequestMessage
->MessageHeader
.MessageSize
=
95 sizeof(EPORT_CONNECT_REQUEST_MESSAGE
) + RequestConnectDataLength
;
96 DPRINT("RequestMessageSize %d\n",
97 RequestMessage
->MessageHeader
.MessageSize
);
98 RequestMessage
->MessageHeader
.SharedSectionSize
= 0;
99 RequestMessage
->ConnectingProcess
= PsGetCurrentProcess();
100 ObReferenceObjectByPointer(RequestMessage
->ConnectingProcess
,
101 PROCESS_VM_OPERATION
,
104 RequestMessage
->SendSectionObject
= (struct _SECTION_OBJECT
*)Section
;
105 RequestMessage
->SendSectionOffset
= SectionOffset
;
106 RequestMessage
->SendViewSize
= ViewSize
;
107 RequestMessage
->ConnectDataLength
= RequestConnectDataLength
;
108 if (RequestConnectDataLength
> 0)
110 memcpy(RequestMessage
->ConnectData
, ConnectData
,
111 RequestConnectDataLength
);
115 * Queue the message to the named port
117 EiReplyOrRequestPort(NamedPort
,
118 &RequestMessage
->MessageHeader
,
119 LPC_CONNECTION_REQUEST
,
121 KeReleaseSemaphore(&NamedPort
->Semaphore
, IO_NO_INCREMENT
, 1, FALSE
);
122 ExFreePool(RequestMessage
);
125 * Wait for them to accept our connection
127 KeWaitForSingleObject(&OurPort
->Semaphore
,
134 * Dequeue the response
136 KeAcquireSpinLock (&OurPort
->Lock
, &oldIrql
);
137 Reply
= EiDequeueMessagePort (OurPort
);
138 KeReleaseSpinLock (&OurPort
->Lock
, oldIrql
);
139 CReply
= (PEPORT_CONNECT_REPLY_MESSAGE
)&Reply
->Message
;
142 * Do some initial cleanup.
144 ObDereferenceObject(PsGetCurrentProcess());
147 * Check for connection refusal.
149 if (CReply
->MessageHeader
.MessageType
== LPC_CONNECTION_REFUSED
)
151 ObDereferenceObject(OurPort
);
154 * FIXME: Check what NT does here. Giving the user data back on
155 * connect failure sounds reasonable; it probably wouldn't break
158 if (ConnectDataLength
!= NULL
)
160 *ConnectDataLength
= CReply
->ConnectDataLength
;
161 memcpy(ConnectData
, CReply
->ConnectData
, CReply
->ConnectDataLength
);
163 return(STATUS_PORT_CONNECTION_REFUSED
);
167 * Otherwise we are connected. Copy data back to the client.
169 *ServerSendViewBase
= CReply
->SendServerViewBase
;
170 *ReceiveViewSize
= CReply
->ReceiveClientViewSize
;
171 *ReceiveViewBase
= CReply
->ReceiveClientViewBase
;
172 *MaximumMessageSize
= CReply
->MaximumMessageSize
;
173 if (ConnectDataLength
!= NULL
)
175 *ConnectDataLength
= CReply
->ConnectDataLength
;
176 memcpy(ConnectData
, CReply
->ConnectData
, CReply
->ConnectDataLength
);
180 * Create our view of the send section object.
184 *ClientSendViewBase
= 0;
185 Status
= MmMapViewOfSection(Section
,
186 PsGetCurrentProcess(),
193 0 /* MEM_TOP_DOWN? */,
195 if (!NT_SUCCESS(Status
))
197 /* FIXME: Cleanup here. */
203 * Do the final initialization of our port.
205 OurPort
->State
= EPORT_CONNECTED_CLIENT
;
211 *ConnectedPort
= OurPort
;
212 return(STATUS_SUCCESS
);
215 /**********************************************************************
220 * Connect to a named port and wait for the other side to
221 * accept the connection.
231 * UserConnectInfoLength
237 NtConnectPort (PHANDLE UnsafeConnectedPortHandle
,
238 PUNICODE_STRING PortName
,
239 PSECURITY_QUALITY_OF_SERVICE Qos
,
240 PLPC_SECTION_WRITE UnsafeWriteMap
,
241 PLPC_SECTION_READ UnsafeReadMap
,
242 PULONG UnsafeMaximumMessageSize
,
243 PVOID UnsafeConnectData
,
244 PULONG UnsafeConnectDataLength
)
246 HANDLE ConnectedPortHandle
;
247 LPC_SECTION_WRITE WriteMap
;
248 LPC_SECTION_READ ReadMap
;
249 ULONG MaximumMessageSize
;
251 ULONG ConnectDataLength
;
252 PSECTION_OBJECT SectionObject
;
253 LARGE_INTEGER SectionOffset
;
254 PEPORT ConnectedPort
;
259 * Copy in write map and partially validate.
261 if (UnsafeWriteMap
!= NULL
)
263 Status
= MmCopyFromCaller(&WriteMap
, UnsafeWriteMap
,
264 sizeof(LPC_SECTION_WRITE
));
265 if (!NT_SUCCESS(Status
))
269 if (WriteMap
.Length
!= sizeof(LPC_SECTION_WRITE
))
271 return(STATUS_INVALID_PARAMETER_4
);
273 SectionOffset
.QuadPart
= WriteMap
.SectionOffset
;
277 WriteMap
.SectionHandle
= INVALID_HANDLE_VALUE
;
281 * Handle connection data.
283 if (UnsafeConnectData
== NULL
)
285 ConnectDataLength
= 0;
290 if (ExGetPreviousMode() == KernelMode
)
292 ConnectDataLength
= *UnsafeConnectDataLength
;
293 ConnectData
= UnsafeConnectData
;
297 Status
= MmCopyFromCaller(&ConnectDataLength
,
298 UnsafeConnectDataLength
,
300 if (!NT_SUCCESS(Status
))
304 ConnectData
= ExAllocatePool(NonPagedPool
, ConnectDataLength
);
305 if (ConnectData
== NULL
&& ConnectDataLength
!= 0)
307 return(STATUS_NO_MEMORY
);
309 Status
= MmCopyFromCaller(ConnectData
,
312 if (!NT_SUCCESS(Status
))
314 ExFreePool(ConnectData
);
321 * Reference the named port.
323 Status
= ObReferenceObjectByName (PortName
,
326 PORT_ALL_ACCESS
, /* DesiredAccess */
331 if (!NT_SUCCESS(Status
))
333 if (KeGetPreviousMode() != KernelMode
)
335 ExFreePool(ConnectData
);
341 * Reference the send section object.
343 if (WriteMap
.SectionHandle
!= INVALID_HANDLE_VALUE
)
345 Status
= ObReferenceObjectByHandle(WriteMap
.SectionHandle
,
346 SECTION_MAP_READ
| SECTION_MAP_WRITE
,
349 (PVOID
*)&SectionObject
,
351 if (!NT_SUCCESS(Status
))
353 ObDereferenceObject(NamedPort
);
354 if (KeGetPreviousMode() != KernelMode
)
356 ExFreePool(ConnectData
);
363 SectionObject
= NULL
;
367 * Do the connection establishment.
369 Status
= EiConnectPort(&ConnectedPort
,
375 &WriteMap
.TargetViewBase
,
381 if (!NT_SUCCESS(Status
))
383 /* FIXME: Again, check what NT does here. */
384 if (UnsafeConnectDataLength
!= NULL
)
386 if (ExGetPreviousMode() != KernelMode
)
388 MmCopyToCaller(UnsafeConnectData
, ConnectData
,
390 ExFreePool(ConnectData
);
392 MmCopyToCaller(UnsafeConnectDataLength
, &ConnectDataLength
,
399 * Do some initial cleanup.
401 if (SectionObject
!= NULL
)
403 ObDereferenceObject(SectionObject
);
404 SectionObject
= NULL
;
406 ObDereferenceObject(NamedPort
);
410 * Copy the data back to the caller.
412 if (ExGetPreviousMode() != KernelMode
)
414 if (UnsafeConnectDataLength
!= NULL
)
416 if (ExGetPreviousMode() != KernelMode
)
418 Status
= MmCopyToCaller(UnsafeConnectData
, ConnectData
,
420 ExFreePool(ConnectData
);
421 if (!NT_SUCCESS(Status
))
426 Status
= MmCopyToCaller(UnsafeConnectDataLength
, &ConnectDataLength
,
428 if (!NT_SUCCESS(Status
))
434 Status
= ObInsertObject(ConnectedPort
,
439 &ConnectedPortHandle
);
440 if (!NT_SUCCESS(Status
))
444 Status
= MmCopyToCaller(UnsafeConnectedPortHandle
, &ConnectedPortHandle
,
446 if (!NT_SUCCESS(Status
))
450 if (UnsafeWriteMap
!= NULL
)
452 Status
= MmCopyToCaller(UnsafeWriteMap
, &WriteMap
,
453 sizeof(LPC_SECTION_WRITE
));
454 if (!NT_SUCCESS(Status
))
459 if (UnsafeReadMap
!= NULL
)
461 Status
= MmCopyToCaller(UnsafeReadMap
, &ReadMap
,
462 sizeof(LPC_SECTION_READ
));
463 if (!NT_SUCCESS(Status
))
468 if (UnsafeMaximumMessageSize
!= NULL
)
470 Status
= MmCopyToCaller(UnsafeMaximumMessageSize
,
472 sizeof(LPC_SECTION_WRITE
));
473 if (!NT_SUCCESS(Status
))
482 ObDereferenceObject(ConnectedPort
);
484 return(STATUS_SUCCESS
);
488 /**********************************************************************
490 * NtAcceptConnectPort@24
505 EXPORTED NTSTATUS STDCALL
506 NtAcceptConnectPort (PHANDLE ServerPortHandle
,
507 HANDLE NamedPortHandle
,
508 PLPC_MESSAGE LpcMessage
,
510 PLPC_SECTION_WRITE WriteMap
,
511 PLPC_SECTION_READ ReadMap
)
515 PEPORT OurPort
= NULL
;
516 PQUEUEDMESSAGE ConnectionRequest
;
518 PEPORT_CONNECT_REQUEST_MESSAGE CRequest
;
519 PEPORT_CONNECT_REPLY_MESSAGE CReply
;
521 CReply
= ExAllocatePool(NonPagedPool
,
522 sizeof(EPORT_CONNECT_REPLY_MESSAGE
) + LpcMessage
->DataSize
);
525 return(STATUS_NO_MEMORY
);
528 Status
= ObReferenceObjectByHandle(NamedPortHandle
,
534 if (!NT_SUCCESS(Status
))
541 * Create a port object for our side of the connection
545 Status
= ObCreateObject(ServerPortHandle
,
550 if (!NT_SUCCESS(Status
))
552 ObDereferenceObject(NamedPort
);
555 NiInitializePort(OurPort
);
559 * Dequeue the connection request
561 KeAcquireSpinLock(&NamedPort
->Lock
, &oldIrql
);
562 ConnectionRequest
= EiDequeueConnectMessagePort (NamedPort
);
563 KeReleaseSpinLock(&NamedPort
->Lock
, oldIrql
);
564 CRequest
= (PEPORT_CONNECT_REQUEST_MESSAGE
)(&ConnectionRequest
->Message
);
569 if (LpcMessage
!= NULL
)
571 memcpy(&CReply
->MessageHeader
, LpcMessage
, sizeof(LPC_MESSAGE_HEADER
));
572 memcpy(&CReply
->ConnectData
, (PVOID
)(LpcMessage
+ 1),
573 LpcMessage
->DataSize
);
574 CReply
->MessageHeader
.MessageSize
=
575 sizeof(EPORT_CONNECT_REPLY_MESSAGE
) + LpcMessage
->DataSize
;
576 CReply
->MessageHeader
.DataSize
= CReply
->MessageHeader
.MessageSize
-
577 sizeof(LPC_MESSAGE_HEADER
);
578 CReply
->ConnectDataLength
= LpcMessage
->DataSize
;
582 CReply
->MessageHeader
.MessageSize
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
);
583 CReply
->MessageHeader
.DataSize
= sizeof(EPORT_CONNECT_REPLY_MESSAGE
) -
584 sizeof(LPC_MESSAGE_HEADER
);
585 CReply
->ConnectDataLength
= 0;
589 EiReplyOrRequestPort(ConnectionRequest
->Sender
,
590 &CReply
->MessageHeader
,
591 LPC_CONNECTION_REFUSED
,
593 KeReleaseSemaphore(&ConnectionRequest
->Sender
->Semaphore
,
597 ObDereferenceObject(ConnectionRequest
->Sender
);
598 ExFreePool(ConnectionRequest
);
600 ObDereferenceObject(NamedPort
);
601 return (STATUS_SUCCESS
);
605 * Prepare the connection.
607 if (WriteMap
!= NULL
)
609 PSECTION_OBJECT SectionObject
;
610 LARGE_INTEGER SectionOffset
;
612 Status
= ObReferenceObjectByHandle(WriteMap
->SectionHandle
,
613 SECTION_MAP_READ
| SECTION_MAP_WRITE
,
616 (PVOID
*)&SectionObject
,
618 if (!NT_SUCCESS(Status
))
623 SectionOffset
.QuadPart
= WriteMap
->SectionOffset
;
624 WriteMap
->TargetViewBase
= 0;
625 CReply
->ReceiveClientViewSize
= WriteMap
->ViewSize
;
626 Status
= MmMapViewOfSection(SectionObject
,
627 CRequest
->ConnectingProcess
,
628 &WriteMap
->TargetViewBase
,
630 CReply
->ReceiveClientViewSize
,
632 &CReply
->ReceiveClientViewSize
,
634 0 /* MEM_TOP_DOWN? */,
636 if (!NT_SUCCESS(Status
))
641 WriteMap
->ViewBase
= 0;
642 Status
= MmMapViewOfSection(SectionObject
,
643 PsGetCurrentProcess(),
650 0 /* MEM_TOP_DOWN? */,
652 if (!NT_SUCCESS(Status
))
657 ObDereferenceObject(SectionObject
);
659 if (ReadMap
!= NULL
&& CRequest
->SendSectionObject
!= NULL
)
661 LARGE_INTEGER SectionOffset
;
663 SectionOffset
= CRequest
->SendSectionOffset
;
664 ReadMap
->ViewSize
= CRequest
->SendViewSize
;
665 ReadMap
->ViewBase
= 0;
666 Status
= MmMapViewOfSection(CRequest
->SendSectionObject
,
667 PsGetCurrentProcess(),
670 CRequest
->SendViewSize
,
672 &CRequest
->SendViewSize
,
674 0 /* MEM_TOP_DOWN? */,
676 if (!NT_SUCCESS(Status
))
687 CReply
->SendServerViewBase
= ReadMap
->ViewBase
;
691 CReply
->SendServerViewBase
= 0;
693 if (WriteMap
!= NULL
)
695 CReply
->ReceiveClientViewBase
= WriteMap
->TargetViewBase
;
697 CReply
->MaximumMessageSize
= 0x148;
701 * Connect the two ports
703 OurPort
->OtherPort
= ConnectionRequest
->Sender
;
704 OurPort
->OtherPort
->OtherPort
= OurPort
;
705 EiReplyOrRequestPort(ConnectionRequest
->Sender
,
706 (PLPC_MESSAGE
)CReply
,
709 ExFreePool(ConnectionRequest
);
711 ObDereferenceObject(OurPort
);
712 ObDereferenceObject(NamedPort
);
714 return (STATUS_SUCCESS
);
717 /**********************************************************************
719 * NtSecureConnectPort@36
722 * Connect to a named port and wait for the other side to
723 * accept the connection. Possibly verify that the server
724 * matches the ServerSid (trusted server).
736 * UserConnectInfoLength
742 NtSecureConnectPort (OUT PHANDLE ConnectedPort
,
743 IN PUNICODE_STRING PortName
,
744 IN PSECURITY_QUALITY_OF_SERVICE Qos
,
745 IN OUT PLPC_SECTION_WRITE WriteMap OPTIONAL
,
746 IN PSID ServerSid OPTIONAL
,
747 IN OUT PLPC_SECTION_READ ReadMap OPTIONAL
,
748 OUT PULONG MaxMessageSize OPTIONAL
,
749 IN OUT PVOID ConnectInfo OPTIONAL
,
750 IN OUT PULONG UserConnectInfoLength OPTIONAL
)
752 return (STATUS_NOT_IMPLEMENTED
);