Reverted latest changes.
[reactos.git] / reactos / ntoskrnl / lpc / connect.c
1 /* $Id: connect.c,v 1.12 2002/09/08 10:23:32 chorns Exp $
2 *
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)
8 * UPDATE HISTORY:
9 * Created 22/05/98
10 */
11
12 /* INCLUDES *****************************************************************/
13
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>
21
22 #define NDEBUG
23 #include <internal/debug.h>
24
25 /* GLOBALS *******************************************************************/
26
27 #define TAG_LPC_CONNECT_MESSAGE TAG('L', 'P', 'C', 'C')
28
29 /* FUNCTIONS *****************************************************************/
30
31 NTSTATUS STDCALL
32 EiConnectPort(IN PEPORT* ConnectedPort,
33 IN PEPORT NamedPort,
34 IN PSECTION_OBJECT Section,
35 IN LARGE_INTEGER SectionOffset,
36 IN ULONG ViewSize,
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)
44 {
45 PEPORT_CONNECT_REQUEST_MESSAGE RequestMessage;
46 ULONG RequestConnectDataLength;
47 PEPORT OurPort;
48 PQUEUEDMESSAGE Reply;
49 PEPORT_CONNECT_REPLY_MESSAGE CReply;
50 NTSTATUS Status;
51 KIRQL oldIrql;
52
53 if (ConnectDataLength == NULL)
54 {
55 RequestConnectDataLength = 0;
56 }
57 else
58 {
59 RequestConnectDataLength = *ConnectDataLength;
60 }
61
62 /*
63 * Create a port to represent our side of the connection
64 */
65 Status = ObCreateObject (NULL,
66 PORT_ALL_ACCESS,
67 NULL,
68 ExPortType,
69 (PVOID*)&OurPort);
70 if (!NT_SUCCESS(Status))
71 {
72 return (Status);
73 }
74 NiInitializePort(OurPort);
75
76 /*
77 * Allocate a request message.
78 */
79 RequestMessage = ExAllocatePool(NonPagedPool,
80 sizeof(EPORT_CONNECT_REQUEST_MESSAGE) +
81 RequestConnectDataLength);
82 if (RequestMessage == NULL)
83 {
84 ObDereferenceObject(OurPort);
85 return(STATUS_NO_MEMORY);
86 }
87
88 /*
89 * Initialize the request message.
90 */
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,
102 NULL,
103 KernelMode);
104 RequestMessage->SendSectionObject = (struct _SECTION_OBJECT*)Section;
105 RequestMessage->SendSectionOffset = SectionOffset;
106 RequestMessage->SendViewSize = ViewSize;
107 RequestMessage->ConnectDataLength = RequestConnectDataLength;
108 if (RequestConnectDataLength > 0)
109 {
110 memcpy(RequestMessage->ConnectData, ConnectData,
111 RequestConnectDataLength);
112 }
113
114 /*
115 * Queue the message to the named port
116 */
117 EiReplyOrRequestPort(NamedPort,
118 &RequestMessage->MessageHeader,
119 LPC_CONNECTION_REQUEST,
120 OurPort);
121 KeReleaseSemaphore(&NamedPort->Semaphore, IO_NO_INCREMENT, 1, FALSE);
122 ExFreePool(RequestMessage);
123
124 /*
125 * Wait for them to accept our connection
126 */
127 KeWaitForSingleObject(&OurPort->Semaphore,
128 UserRequest,
129 UserMode,
130 FALSE,
131 NULL);
132
133 /*
134 * Dequeue the response
135 */
136 KeAcquireSpinLock (&OurPort->Lock, &oldIrql);
137 Reply = EiDequeueMessagePort (OurPort);
138 KeReleaseSpinLock (&OurPort->Lock, oldIrql);
139 CReply = (PEPORT_CONNECT_REPLY_MESSAGE)&Reply->Message;
140
141 /*
142 * Do some initial cleanup.
143 */
144 ObDereferenceObject(PsGetCurrentProcess());
145
146 /*
147 * Check for connection refusal.
148 */
149 if (CReply->MessageHeader.MessageType == LPC_CONNECTION_REFUSED)
150 {
151 ObDereferenceObject(OurPort);
152 ExFreePool(Reply);
153 /*
154 * FIXME: Check what NT does here. Giving the user data back on
155 * connect failure sounds reasonable; it probably wouldn't break
156 * anything anyway.
157 */
158 if (ConnectDataLength != NULL)
159 {
160 *ConnectDataLength = CReply->ConnectDataLength;
161 memcpy(ConnectData, CReply->ConnectData, CReply->ConnectDataLength);
162 }
163 return(STATUS_PORT_CONNECTION_REFUSED);
164 }
165
166 /*
167 * Otherwise we are connected. Copy data back to the client.
168 */
169 *ServerSendViewBase = CReply->SendServerViewBase;
170 *ReceiveViewSize = CReply->ReceiveClientViewSize;
171 *ReceiveViewBase = CReply->ReceiveClientViewBase;
172 *MaximumMessageSize = CReply->MaximumMessageSize;
173 if (ConnectDataLength != NULL)
174 {
175 *ConnectDataLength = CReply->ConnectDataLength;
176 memcpy(ConnectData, CReply->ConnectData, CReply->ConnectDataLength);
177 }
178
179 /*
180 * Create our view of the send section object.
181 */
182 if (Section != NULL)
183 {
184 *ClientSendViewBase = 0;
185 Status = MmMapViewOfSection(Section,
186 PsGetCurrentProcess(),
187 ClientSendViewBase,
188 0,
189 ViewSize,
190 &SectionOffset,
191 &ViewSize,
192 ViewUnmap,
193 0 /* MEM_TOP_DOWN? */,
194 PAGE_READWRITE);
195 if (!NT_SUCCESS(Status))
196 {
197 /* FIXME: Cleanup here. */
198 return(Status);
199 }
200 }
201
202 /*
203 * Do the final initialization of our port.
204 */
205 OurPort->State = EPORT_CONNECTED_CLIENT;
206
207 /*
208 * Cleanup.
209 */
210 ExFreePool(Reply);
211 *ConnectedPort = OurPort;
212 return(STATUS_SUCCESS);
213 }
214
215 /**********************************************************************
216 * NAME EXPORTED
217 * NtConnectPort@32
218 *
219 * DESCRIPTION
220 * Connect to a named port and wait for the other side to
221 * accept the connection.
222 *
223 * ARGUMENTS
224 * ConnectedPort
225 * PortName
226 * Qos
227 * WriteMap
228 * ReadMap
229 * MaxMessageSize
230 * ConnectInfo
231 * UserConnectInfoLength
232 *
233 * RETURN VALUE
234 *
235 */
236 NTSTATUS STDCALL
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)
245 {
246 HANDLE ConnectedPortHandle;
247 LPC_SECTION_WRITE WriteMap;
248 LPC_SECTION_READ ReadMap;
249 ULONG MaximumMessageSize;
250 PVOID ConnectData;
251 ULONG ConnectDataLength;
252 PSECTION_OBJECT SectionObject;
253 LARGE_INTEGER SectionOffset;
254 PEPORT ConnectedPort;
255 NTSTATUS Status;
256 PEPORT NamedPort;
257
258 /*
259 * Copy in write map and partially validate.
260 */
261 if (UnsafeWriteMap != NULL)
262 {
263 Status = MmCopyFromCaller(&WriteMap, UnsafeWriteMap,
264 sizeof(LPC_SECTION_WRITE));
265 if (!NT_SUCCESS(Status))
266 {
267 return(Status);
268 }
269 if (WriteMap.Length != sizeof(LPC_SECTION_WRITE))
270 {
271 return(STATUS_INVALID_PARAMETER_4);
272 }
273 SectionOffset.QuadPart = WriteMap.SectionOffset;
274 }
275 else
276 {
277 WriteMap.SectionHandle = INVALID_HANDLE_VALUE;
278 }
279
280 /*
281 * Handle connection data.
282 */
283 if (UnsafeConnectData == NULL)
284 {
285 ConnectDataLength = 0;
286 ConnectData = NULL;
287 }
288 else
289 {
290 if (ExGetPreviousMode() == KernelMode)
291 {
292 ConnectDataLength = *UnsafeConnectDataLength;
293 ConnectData = UnsafeConnectData;
294 }
295 else
296 {
297 Status = MmCopyFromCaller(&ConnectDataLength,
298 UnsafeConnectDataLength,
299 sizeof(ULONG));
300 if (!NT_SUCCESS(Status))
301 {
302 return(Status);
303 }
304 ConnectData = ExAllocatePool(NonPagedPool, ConnectDataLength);
305 if (ConnectData == NULL && ConnectDataLength != 0)
306 {
307 return(STATUS_NO_MEMORY);
308 }
309 Status = MmCopyFromCaller(ConnectData,
310 UnsafeConnectData,
311 ConnectDataLength);
312 if (!NT_SUCCESS(Status))
313 {
314 ExFreePool(ConnectData);
315 return(Status);
316 }
317 }
318 }
319
320 /*
321 * Reference the named port.
322 */
323 Status = ObReferenceObjectByName (PortName,
324 0,
325 NULL,
326 PORT_ALL_ACCESS, /* DesiredAccess */
327 ExPortType,
328 UserMode,
329 NULL,
330 (PVOID*)&NamedPort);
331 if (!NT_SUCCESS(Status))
332 {
333 if (KeGetPreviousMode() != KernelMode)
334 {
335 ExFreePool(ConnectData);
336 }
337 return(Status);
338 }
339
340 /*
341 * Reference the send section object.
342 */
343 if (WriteMap.SectionHandle != INVALID_HANDLE_VALUE)
344 {
345 Status = ObReferenceObjectByHandle(WriteMap.SectionHandle,
346 SECTION_MAP_READ | SECTION_MAP_WRITE,
347 MmSectionObjectType,
348 UserMode,
349 (PVOID*)&SectionObject,
350 NULL);
351 if (!NT_SUCCESS(Status))
352 {
353 ObDereferenceObject(NamedPort);
354 if (KeGetPreviousMode() != KernelMode)
355 {
356 ExFreePool(ConnectData);
357 }
358 return(Status);
359 }
360 }
361 else
362 {
363 SectionObject = NULL;
364 }
365
366 /*
367 * Do the connection establishment.
368 */
369 Status = EiConnectPort(&ConnectedPort,
370 NamedPort,
371 SectionObject,
372 SectionOffset,
373 WriteMap.ViewSize,
374 &WriteMap.ViewBase,
375 &WriteMap.TargetViewBase,
376 &ReadMap.ViewSize,
377 &ReadMap.ViewBase,
378 &MaximumMessageSize,
379 ConnectData,
380 &ConnectDataLength);
381 if (!NT_SUCCESS(Status))
382 {
383 /* FIXME: Again, check what NT does here. */
384 if (UnsafeConnectDataLength != NULL)
385 {
386 if (ExGetPreviousMode() != KernelMode)
387 {
388 MmCopyToCaller(UnsafeConnectData, ConnectData,
389 ConnectDataLength);
390 ExFreePool(ConnectData);
391 }
392 MmCopyToCaller(UnsafeConnectDataLength, &ConnectDataLength,
393 sizeof(ULONG));
394 }
395 return(Status);
396 }
397
398 /*
399 * Do some initial cleanup.
400 */
401 if (SectionObject != NULL)
402 {
403 ObDereferenceObject(SectionObject);
404 SectionObject = NULL;
405 }
406 ObDereferenceObject(NamedPort);
407 NamedPort = NULL;
408
409 /*
410 * Copy the data back to the caller.
411 */
412 if (ExGetPreviousMode() != KernelMode)
413 {
414 if (UnsafeConnectDataLength != NULL)
415 {
416 if (ExGetPreviousMode() != KernelMode)
417 {
418 Status = MmCopyToCaller(UnsafeConnectData, ConnectData,
419 ConnectDataLength);
420 ExFreePool(ConnectData);
421 if (!NT_SUCCESS(Status))
422 {
423 return(Status);
424 }
425 }
426 Status = MmCopyToCaller(UnsafeConnectDataLength, &ConnectDataLength,
427 sizeof(ULONG));
428 if (!NT_SUCCESS(Status))
429 {
430 return(Status);
431 }
432 }
433 }
434 Status = ObInsertObject(ConnectedPort,
435 NULL,
436 PORT_ALL_ACCESS,
437 0,
438 NULL,
439 &ConnectedPortHandle);
440 if (!NT_SUCCESS(Status))
441 {
442 return(Status);
443 }
444 Status = MmCopyToCaller(UnsafeConnectedPortHandle, &ConnectedPortHandle,
445 sizeof(HANDLE));
446 if (!NT_SUCCESS(Status))
447 {
448 return(Status);
449 }
450 if (UnsafeWriteMap != NULL)
451 {
452 Status = MmCopyToCaller(UnsafeWriteMap, &WriteMap,
453 sizeof(LPC_SECTION_WRITE));
454 if (!NT_SUCCESS(Status))
455 {
456 return(Status);
457 }
458 }
459 if (UnsafeReadMap != NULL)
460 {
461 Status = MmCopyToCaller(UnsafeReadMap, &ReadMap,
462 sizeof(LPC_SECTION_READ));
463 if (!NT_SUCCESS(Status))
464 {
465 return(Status);
466 }
467 }
468 if (UnsafeMaximumMessageSize != NULL)
469 {
470 Status = MmCopyToCaller(UnsafeMaximumMessageSize,
471 &MaximumMessageSize,
472 sizeof(LPC_SECTION_WRITE));
473 if (!NT_SUCCESS(Status))
474 {
475 return(Status);
476 }
477 }
478
479 /*
480 * All done.
481 */
482 ObDereferenceObject(ConnectedPort);
483
484 return(STATUS_SUCCESS);
485 }
486
487
488 /**********************************************************************
489 * NAME EXPORTED
490 * NtAcceptConnectPort@24
491 *
492 * DESCRIPTION
493 *
494 * ARGUMENTS
495 * ServerPortHandle
496 * NamedPortHandle
497 * LpcMessage
498 * AcceptIt
499 * WriteMap
500 * ReadMap
501 *
502 * RETURN VALUE
503 *
504 */
505 EXPORTED NTSTATUS STDCALL
506 NtAcceptConnectPort (PHANDLE ServerPortHandle,
507 HANDLE NamedPortHandle,
508 PLPC_MESSAGE LpcMessage,
509 BOOLEAN AcceptIt,
510 PLPC_SECTION_WRITE WriteMap,
511 PLPC_SECTION_READ ReadMap)
512 {
513 NTSTATUS Status;
514 PEPORT NamedPort;
515 PEPORT OurPort = NULL;
516 PQUEUEDMESSAGE ConnectionRequest;
517 KIRQL oldIrql;
518 PEPORT_CONNECT_REQUEST_MESSAGE CRequest;
519 PEPORT_CONNECT_REPLY_MESSAGE CReply;
520
521 CReply = ExAllocatePool(NonPagedPool,
522 sizeof(EPORT_CONNECT_REPLY_MESSAGE) + LpcMessage->DataSize);
523 if (CReply == NULL)
524 {
525 return(STATUS_NO_MEMORY);
526 }
527
528 Status = ObReferenceObjectByHandle(NamedPortHandle,
529 PORT_ALL_ACCESS,
530 ExPortType,
531 UserMode,
532 (PVOID*)&NamedPort,
533 NULL);
534 if (!NT_SUCCESS(Status))
535 {
536 ExFreePool(CReply);
537 return (Status);
538 }
539
540 /*
541 * Create a port object for our side of the connection
542 */
543 if (AcceptIt == 1)
544 {
545 Status = ObCreateObject(ServerPortHandle,
546 PORT_ALL_ACCESS,
547 NULL,
548 ExPortType,
549 (PVOID*)&OurPort);
550 if (!NT_SUCCESS(Status))
551 {
552 ObDereferenceObject(NamedPort);
553 return(Status);
554 }
555 NiInitializePort(OurPort);
556 }
557
558 /*
559 * Dequeue the connection request
560 */
561 KeAcquireSpinLock(&NamedPort->Lock, &oldIrql);
562 ConnectionRequest = EiDequeueConnectMessagePort (NamedPort);
563 KeReleaseSpinLock(&NamedPort->Lock, oldIrql);
564 CRequest = (PEPORT_CONNECT_REQUEST_MESSAGE)(&ConnectionRequest->Message);
565
566 /*
567 * Prepare the reply.
568 */
569 if (LpcMessage != NULL)
570 {
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;
579 }
580 else
581 {
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;
586 }
587 if (AcceptIt != 1)
588 {
589 EiReplyOrRequestPort(ConnectionRequest->Sender,
590 &CReply->MessageHeader,
591 LPC_CONNECTION_REFUSED,
592 NamedPort);
593 KeReleaseSemaphore(&ConnectionRequest->Sender->Semaphore,
594 IO_NO_INCREMENT,
595 1,
596 FALSE);
597 ObDereferenceObject(ConnectionRequest->Sender);
598 ExFreePool(ConnectionRequest);
599 ExFreePool(CReply);
600 ObDereferenceObject(NamedPort);
601 return (STATUS_SUCCESS);
602 }
603
604 /*
605 * Prepare the connection.
606 */
607 if (WriteMap != NULL)
608 {
609 PSECTION_OBJECT SectionObject;
610 LARGE_INTEGER SectionOffset;
611
612 Status = ObReferenceObjectByHandle(WriteMap->SectionHandle,
613 SECTION_MAP_READ | SECTION_MAP_WRITE,
614 MmSectionObjectType,
615 UserMode,
616 (PVOID*)&SectionObject,
617 NULL);
618 if (!NT_SUCCESS(Status))
619 {
620 return(Status);
621 }
622
623 SectionOffset.QuadPart = WriteMap->SectionOffset;
624 WriteMap->TargetViewBase = 0;
625 CReply->ReceiveClientViewSize = WriteMap->ViewSize;
626 Status = MmMapViewOfSection(SectionObject,
627 CRequest->ConnectingProcess,
628 &WriteMap->TargetViewBase,
629 0,
630 CReply->ReceiveClientViewSize,
631 &SectionOffset,
632 &CReply->ReceiveClientViewSize,
633 ViewUnmap,
634 0 /* MEM_TOP_DOWN? */,
635 PAGE_READWRITE);
636 if (!NT_SUCCESS(Status))
637 {
638 return(Status);
639 }
640
641 WriteMap->ViewBase = 0;
642 Status = MmMapViewOfSection(SectionObject,
643 PsGetCurrentProcess(),
644 &WriteMap->ViewBase,
645 0,
646 WriteMap->ViewSize,
647 &SectionOffset,
648 &WriteMap->ViewSize,
649 ViewUnmap,
650 0 /* MEM_TOP_DOWN? */,
651 PAGE_READWRITE);
652 if (!NT_SUCCESS(Status))
653 {
654 return(Status);
655 }
656
657 ObDereferenceObject(SectionObject);
658 }
659 if (ReadMap != NULL && CRequest->SendSectionObject != NULL)
660 {
661 LARGE_INTEGER SectionOffset;
662
663 SectionOffset = CRequest->SendSectionOffset;
664 ReadMap->ViewSize = CRequest->SendViewSize;
665 ReadMap->ViewBase = 0;
666 Status = MmMapViewOfSection(CRequest->SendSectionObject,
667 PsGetCurrentProcess(),
668 &ReadMap->ViewBase,
669 0,
670 CRequest->SendViewSize,
671 &SectionOffset,
672 &CRequest->SendViewSize,
673 ViewUnmap,
674 0 /* MEM_TOP_DOWN? */,
675 PAGE_READWRITE);
676 if (!NT_SUCCESS(Status))
677 {
678 return(Status);
679 }
680 }
681
682 /*
683 * Finish the reply.
684 */
685 if (ReadMap != NULL)
686 {
687 CReply->SendServerViewBase = ReadMap->ViewBase;
688 }
689 else
690 {
691 CReply->SendServerViewBase = 0;
692 }
693 if (WriteMap != NULL)
694 {
695 CReply->ReceiveClientViewBase = WriteMap->TargetViewBase;
696 }
697 CReply->MaximumMessageSize = 0x148;
698
699
700 /*
701 * Connect the two ports
702 */
703 OurPort->OtherPort = ConnectionRequest->Sender;
704 OurPort->OtherPort->OtherPort = OurPort;
705 EiReplyOrRequestPort(ConnectionRequest->Sender,
706 (PLPC_MESSAGE)CReply,
707 LPC_REPLY,
708 OurPort);
709 ExFreePool(ConnectionRequest);
710
711 ObDereferenceObject(OurPort);
712 ObDereferenceObject(NamedPort);
713
714 return (STATUS_SUCCESS);
715 }
716
717 /**********************************************************************
718 * NAME EXPORTED
719 * NtSecureConnectPort@36
720 *
721 * DESCRIPTION
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).
725 * Present in w2k+.
726 *
727 * ARGUMENTS
728 * ConnectedPort
729 * PortName
730 * Qos
731 * WriteMap
732 * ServerSid
733 * ReadMap
734 * MaxMessageSize
735 * ConnectInfo
736 * UserConnectInfoLength
737 *
738 * RETURN VALUE
739 *
740 */
741 NTSTATUS STDCALL
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)
751 {
752 return (STATUS_NOT_IMPLEMENTED);
753 }
754
755 /* EOF */