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