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