update for HEAD-2002110701
[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 #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);
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   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 = ObCreateObject(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  */
749 NTSTATUS STDCALL
750 NtSecureConnectPort (OUT    PHANDLE                             ConnectedPort,
751                      IN     PUNICODE_STRING                     PortName,
752                      IN     PSECURITY_QUALITY_OF_SERVICE        Qos,
753                      IN OUT PLPC_SECTION_WRITE                  WriteMap                OPTIONAL,
754                      IN     PSID                                ServerSid               OPTIONAL,
755                      IN OUT PLPC_SECTION_READ                   ReadMap                 OPTIONAL,
756                      OUT    PULONG                              MaxMessageSize          OPTIONAL,
757                      IN OUT PVOID                               ConnectInfo             OPTIONAL,
758                      IN OUT PULONG                              UserConnectInfoLength   OPTIONAL)
759 {
760         return (STATUS_NOT_IMPLEMENTED);
761 }
762
763 /* EOF */