xref: /reactos/ntoskrnl/lpc/connect.c (revision 84344399)
1 /*
2  * PROJECT:         ReactOS Kernel
3  * LICENSE:         GPL - See COPYING in the top level directory
4  * FILE:            ntoskrnl/lpc/connect.c
5  * PURPOSE:         Local Procedure Call: Connection Management
6  * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14 
15 /* PRIVATE FUNCTIONS *********************************************************/
16 
17 PVOID
18 NTAPI
19 LpcpFreeConMsg(IN OUT PLPCP_MESSAGE *Message,
20                IN OUT PLPCP_CONNECTION_MESSAGE *ConnectMessage,
21                IN PETHREAD CurrentThread)
22 {
23     PVOID SectionToMap;
24     PLPCP_MESSAGE ReplyMessage;
25 
26     /* Acquire the LPC lock */
27     KeAcquireGuardedMutex(&LpcpLock);
28 
29     /* Check if the reply chain is not empty */
30     if (!IsListEmpty(&CurrentThread->LpcReplyChain))
31     {
32         /* Remove this entry and re-initialize it */
33         RemoveEntryList(&CurrentThread->LpcReplyChain);
34         InitializeListHead(&CurrentThread->LpcReplyChain);
35     }
36 
37     /* Check if there's a reply message */
38     ReplyMessage = LpcpGetMessageFromThread(CurrentThread);
39     if (ReplyMessage)
40     {
41         /* Get the message */
42         *Message = ReplyMessage;
43 
44         /* Check if it's got messages */
45         if (!IsListEmpty(&ReplyMessage->Entry))
46         {
47             /* Clear the list */
48             RemoveEntryList(&ReplyMessage->Entry);
49             InitializeListHead(&ReplyMessage->Entry);
50         }
51 
52         /* Clear message data */
53         CurrentThread->LpcReceivedMessageId = 0;
54         CurrentThread->LpcReplyMessage = NULL;
55 
56         /* Get the connection message and clear the section */
57         *ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(ReplyMessage + 1);
58         SectionToMap = (*ConnectMessage)->SectionToMap;
59         (*ConnectMessage)->SectionToMap = NULL;
60     }
61     else
62     {
63         /* No message to return */
64         *Message = NULL;
65         SectionToMap = NULL;
66     }
67 
68     /* Release the lock and return the section */
69     KeReleaseGuardedMutex(&LpcpLock);
70     return SectionToMap;
71 }
72 
73 /* PUBLIC FUNCTIONS **********************************************************/
74 
75 /*
76  * @implemented
77  */
78 NTSTATUS
79 NTAPI
80 NtSecureConnectPort(OUT PHANDLE PortHandle,
81                     IN PUNICODE_STRING PortName,
82                     IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
83                     IN OUT PPORT_VIEW ClientView OPTIONAL,
84                     IN PSID ServerSid OPTIONAL,
85                     IN OUT PREMOTE_PORT_VIEW ServerView OPTIONAL,
86                     OUT PULONG MaxMessageLength OPTIONAL,
87                     IN OUT PVOID ConnectionInformation OPTIONAL,
88                     IN OUT PULONG ConnectionInformationLength OPTIONAL)
89 {
90     NTSTATUS Status = STATUS_SUCCESS;
91     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
92     PETHREAD Thread = PsGetCurrentThread();
93 #if DBG
94     UNICODE_STRING CapturedPortName;
95 #endif
96     SECURITY_QUALITY_OF_SERVICE CapturedQos;
97     PORT_VIEW CapturedClientView;
98     PSID CapturedServerSid;
99     ULONG ConnectionInfoLength = 0;
100     PLPCP_PORT_OBJECT Port, ClientPort;
101     PLPCP_MESSAGE Message;
102     PLPCP_CONNECTION_MESSAGE ConnectMessage;
103     ULONG PortMessageLength;
104     HANDLE Handle;
105     PVOID SectionToMap;
106     LARGE_INTEGER SectionOffset;
107     PTOKEN Token;
108     PTOKEN_USER TokenUserInfo;
109 
110     PAGED_CODE();
111 
112     /* Check if the call comes from user mode */
113     if (PreviousMode != KernelMode)
114     {
115         /* Enter SEH for probing the parameters */
116         _SEH2_TRY
117         {
118             /* Probe the PortHandle */
119             ProbeForWriteHandle(PortHandle);
120 
121             /* Probe and capture the QoS */
122             ProbeForRead(SecurityQos, sizeof(*SecurityQos), sizeof(ULONG));
123             CapturedQos = *(volatile SECURITY_QUALITY_OF_SERVICE*)SecurityQos;
124             /* NOTE: Do not care about CapturedQos.Length */
125 
126             /* The following parameters are optional */
127 
128             /* Capture the client view */
129             if (ClientView)
130             {
131                 ProbeForWrite(ClientView, sizeof(*ClientView), sizeof(ULONG));
132                 CapturedClientView = *(volatile PORT_VIEW*)ClientView;
133 
134                 /* Validate the size of the client view */
135                 if (CapturedClientView.Length != sizeof(CapturedClientView))
136                 {
137                     /* Invalid size */
138                     _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
139                 }
140             }
141 
142             /* Capture the server view */
143             if (ServerView)
144             {
145                 ProbeForWrite(ServerView, sizeof(*ServerView), sizeof(ULONG));
146 
147                 /* Validate the size of the server view */
148                 if (((volatile REMOTE_PORT_VIEW*)ServerView)->Length != sizeof(*ServerView))
149                 {
150                     /* Invalid size */
151                     _SEH2_YIELD(return STATUS_INVALID_PARAMETER);
152                 }
153             }
154 
155             if (MaxMessageLength)
156                 ProbeForWriteUlong(MaxMessageLength);
157 
158             /* Capture connection information length */
159             if (ConnectionInformationLength)
160             {
161                 ProbeForWriteUlong(ConnectionInformationLength);
162                 ConnectionInfoLength = *(volatile ULONG*)ConnectionInformationLength;
163             }
164 
165             /* Probe the ConnectionInformation */
166             if (ConnectionInformation)
167                 ProbeForWrite(ConnectionInformation, ConnectionInfoLength, sizeof(ULONG));
168 
169             CapturedServerSid = ServerSid;
170             if (ServerSid)
171             {
172                 /* Capture it */
173                 Status = SepCaptureSid(ServerSid,
174                                        PreviousMode,
175                                        PagedPool,
176                                        TRUE,
177                                        &CapturedServerSid);
178                 if (!NT_SUCCESS(Status))
179                 {
180                     DPRINT1("Failed to capture ServerSid!\n");
181                     _SEH2_YIELD(return Status);
182                 }
183             }
184         }
185         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
186         {
187             /* There was an exception, return the exception code */
188             _SEH2_YIELD(return _SEH2_GetExceptionCode());
189         }
190         _SEH2_END;
191     }
192     else
193     {
194         CapturedQos = *SecurityQos;
195         /* NOTE: Do not care about CapturedQos.Length */
196 
197         /* The following parameters are optional */
198 
199         /* Capture the client view */
200         if (ClientView)
201         {
202             /* Validate the size of the client view */
203             if (ClientView->Length != sizeof(*ClientView))
204             {
205                 /* Invalid size */
206                 return STATUS_INVALID_PARAMETER;
207             }
208             CapturedClientView = *ClientView;
209         }
210 
211         /* Capture the server view */
212         if (ServerView)
213         {
214             /* Validate the size of the server view */
215             if (ServerView->Length != sizeof(*ServerView))
216             {
217                 /* Invalid size */
218                 return STATUS_INVALID_PARAMETER;
219             }
220         }
221 
222         /* Capture connection information length */
223         if (ConnectionInformationLength)
224             ConnectionInfoLength = *ConnectionInformationLength;
225 
226         CapturedServerSid = ServerSid;
227     }
228 
229 #if DBG
230     /* Capture the port name for DPRINT only - ObReferenceObjectByName does
231      * its own capture. As it is used only for debugging, ignore any failure;
232      * the string is zeroed out in such case. */
233     ProbeAndCaptureUnicodeString(&CapturedPortName, PreviousMode, PortName);
234 
235     LPCTRACE(LPC_CONNECT_DEBUG,
236              "Name: %wZ. SecurityQos: %p. Views: %p/%p. Sid: %p\n",
237              &CapturedPortName,
238              SecurityQos,
239              ClientView,
240              ServerView,
241              ServerSid);
242 #endif
243 
244     /* Get the port */
245     Status = ObReferenceObjectByName(PortName,
246                                      0,
247                                      NULL,
248                                      PORT_CONNECT,
249                                      LpcPortObjectType,
250                                      PreviousMode,
251                                      NULL,
252                                      (PVOID*)&Port);
253     if (!NT_SUCCESS(Status))
254     {
255 #if DBG
256         DPRINT1("Failed to reference port '%wZ': 0x%lx\n", &CapturedPortName, Status);
257         ReleaseCapturedUnicodeString(&CapturedPortName, PreviousMode);
258 #endif
259 
260         if (CapturedServerSid != ServerSid)
261             SepReleaseSid(CapturedServerSid, PreviousMode, TRUE);
262 
263         return Status;
264     }
265 
266     /* This has to be a connection port */
267     if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
268     {
269 #if DBG
270         DPRINT1("Port '%wZ' is not a connection port (Flags: 0x%lx)\n", &CapturedPortName, Port->Flags);
271         ReleaseCapturedUnicodeString(&CapturedPortName, PreviousMode);
272 #endif
273 
274         /* It isn't, so fail */
275         ObDereferenceObject(Port);
276 
277         if (CapturedServerSid != ServerSid)
278             SepReleaseSid(CapturedServerSid, PreviousMode, TRUE);
279 
280         return STATUS_INVALID_PORT_HANDLE;
281     }
282 
283     /* Check if we have a (captured) SID */
284     if (ServerSid)
285     {
286         /* Make sure that we have a server */
287         if (Port->ServerProcess)
288         {
289             /* Get its token and query user information */
290             Token = PsReferencePrimaryToken(Port->ServerProcess);
291             Status = SeQueryInformationToken(Token, TokenUser, (PVOID*)&TokenUserInfo);
292             PsDereferencePrimaryToken(Token);
293 
294             /* Check for success */
295             if (NT_SUCCESS(Status))
296             {
297                 /* Compare the SIDs */
298                 if (!RtlEqualSid(CapturedServerSid, TokenUserInfo->User.Sid))
299                 {
300                     /* Fail */
301 #if DBG
302                     DPRINT1("Port '%wZ': server SID mismatch\n", &CapturedPortName);
303 #endif
304                     Status = STATUS_SERVER_SID_MISMATCH;
305                 }
306 
307                 /* Free token information */
308                 ExFreePoolWithTag(TokenUserInfo, TAG_SE);
309             }
310         }
311         else
312         {
313             /* Invalid SID */
314 #if DBG
315             DPRINT1("Port '%wZ': server SID mismatch\n", &CapturedPortName);
316 #endif
317             Status = STATUS_SERVER_SID_MISMATCH;
318         }
319 
320         /* Finally release the captured SID, we don't need it anymore */
321         if (CapturedServerSid != ServerSid)
322             SepReleaseSid(CapturedServerSid, PreviousMode, TRUE);
323     }
324 
325 #if DBG
326     ReleaseCapturedUnicodeString(&CapturedPortName, PreviousMode);
327 #endif
328 
329     /* Check if SID failed */
330     if (ServerSid && !NT_SUCCESS(Status))
331     {
332         /* Quit */
333         ObDereferenceObject(Port);
334         return Status;
335     }
336 
337     /* Create the client port */
338     Status = ObCreateObject(PreviousMode,
339                             LpcPortObjectType,
340                             NULL,
341                             PreviousMode,
342                             NULL,
343                             sizeof(LPCP_PORT_OBJECT),
344                             0,
345                             0,
346                             (PVOID*)&ClientPort);
347     if (!NT_SUCCESS(Status))
348     {
349         /* Failed, dereference the server port and return */
350         DPRINT1("Failed to create Port object: 0x%lx\n", Status);
351         ObDereferenceObject(Port);
352         return Status;
353     }
354 
355     /*
356      * Setup the client port -- From now on, dereferencing the client port
357      * will automatically dereference the connection port too.
358      */
359     RtlZeroMemory(ClientPort, sizeof(LPCP_PORT_OBJECT));
360     ClientPort->Flags = LPCP_CLIENT_PORT;
361     ClientPort->ConnectionPort = Port;
362     ClientPort->MaxMessageLength = Port->MaxMessageLength;
363     ClientPort->SecurityQos = CapturedQos;
364     InitializeListHead(&ClientPort->LpcReplyChainHead);
365     InitializeListHead(&ClientPort->LpcDataInfoChainHead);
366 
367     /* Check if we have dynamic security */
368     if (CapturedQos.ContextTrackingMode == SECURITY_DYNAMIC_TRACKING)
369     {
370         /* Remember that */
371         ClientPort->Flags |= LPCP_SECURITY_DYNAMIC;
372     }
373     else
374     {
375         /* Create our own client security */
376         Status = SeCreateClientSecurity(Thread,
377                                         &CapturedQos,
378                                         FALSE,
379                                         &ClientPort->StaticSecurity);
380         if (!NT_SUCCESS(Status))
381         {
382             /* Security failed, dereference and return */
383             DPRINT1("SeCreateClientSecurity failed: 0x%lx\n", Status);
384             ObDereferenceObject(ClientPort);
385             return Status;
386         }
387     }
388 
389     /* Initialize the port queue */
390     Status = LpcpInitializePortQueue(ClientPort);
391     if (!NT_SUCCESS(Status))
392     {
393         /* Failed */
394         DPRINT1("LpcpInitializePortQueue failed: 0x%lx\n", Status);
395         ObDereferenceObject(ClientPort);
396         return Status;
397     }
398 
399     /* Check if we have a client view */
400     if (ClientView)
401     {
402         /* Get the section handle */
403         Status = ObReferenceObjectByHandle(CapturedClientView.SectionHandle,
404                                            SECTION_MAP_READ |
405                                            SECTION_MAP_WRITE,
406                                            MmSectionObjectType,
407                                            PreviousMode,
408                                            (PVOID*)&SectionToMap,
409                                            NULL);
410         if (!NT_SUCCESS(Status))
411         {
412             /* Fail */
413             DPRINT1("Failed to reference port section handle: 0x%lx\n", Status);
414             ObDereferenceObject(ClientPort);
415             return Status;
416         }
417 
418         /* Set the section offset */
419         SectionOffset.QuadPart = CapturedClientView.SectionOffset;
420 
421         /* Map it */
422         Status = MmMapViewOfSection(SectionToMap,
423                                     PsGetCurrentProcess(),
424                                     &ClientPort->ClientSectionBase,
425                                     0,
426                                     0,
427                                     &SectionOffset,
428                                     &CapturedClientView.ViewSize,
429                                     ViewUnmap,
430                                     0,
431                                     PAGE_READWRITE);
432 
433         /* Update the offset */
434         CapturedClientView.SectionOffset = SectionOffset.LowPart;
435 
436         /* Check for failure */
437         if (!NT_SUCCESS(Status))
438         {
439             /* Fail */
440             DPRINT1("Failed to map port section: 0x%lx\n", Status);
441             ObDereferenceObject(SectionToMap);
442             ObDereferenceObject(ClientPort);
443             return Status;
444         }
445 
446         /* Update the base */
447         CapturedClientView.ViewBase = ClientPort->ClientSectionBase;
448 
449         /* Reference and remember the process */
450         ClientPort->MappingProcess = PsGetCurrentProcess();
451         ObReferenceObject(ClientPort->MappingProcess);
452     }
453     else
454     {
455         /* No section */
456         SectionToMap = NULL;
457     }
458 
459     /* Normalize connection information */
460     if (ConnectionInfoLength > Port->MaxConnectionInfoLength)
461     {
462         /* Use the port's maximum allowed value */
463         ConnectionInfoLength = Port->MaxConnectionInfoLength;
464     }
465 
466     /* Allocate a message from the port zone */
467     Message = LpcpAllocateFromPortZone();
468     if (!Message)
469     {
470         /* Fail if we couldn't allocate a message */
471         DPRINT1("LpcpAllocateFromPortZone failed\n");
472         if (SectionToMap) ObDereferenceObject(SectionToMap);
473         ObDereferenceObject(ClientPort);
474         return STATUS_NO_MEMORY;
475     }
476 
477     /* Set pointer to the connection message and fill in the CID */
478     ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
479     Message->Request.ClientId = Thread->Cid;
480 
481     /* Check if we have a client view */
482     if (ClientView)
483     {
484         /* Set the view size */
485         Message->Request.ClientViewSize = CapturedClientView.ViewSize;
486 
487         /* Copy the client view and clear the server view */
488         RtlCopyMemory(&ConnectMessage->ClientView,
489                       &CapturedClientView,
490                       sizeof(CapturedClientView));
491         RtlZeroMemory(&ConnectMessage->ServerView, sizeof(REMOTE_PORT_VIEW));
492     }
493     else
494     {
495         /* Set the size to 0 and clear the connect message */
496         Message->Request.ClientViewSize = 0;
497         RtlZeroMemory(ConnectMessage, sizeof(LPCP_CONNECTION_MESSAGE));
498     }
499 
500     /* Set the section and client port. Port is NULL for now */
501     ConnectMessage->ClientPort = NULL;
502     ConnectMessage->SectionToMap = SectionToMap;
503 
504     /* Set the data for the connection request message */
505     Message->Request.u1.s1.DataLength = (CSHORT)ConnectionInfoLength +
506                                          sizeof(LPCP_CONNECTION_MESSAGE);
507     Message->Request.u1.s1.TotalLength = sizeof(LPCP_MESSAGE) +
508                                          Message->Request.u1.s1.DataLength;
509     Message->Request.u2.s2.Type = LPC_CONNECTION_REQUEST;
510 
511     /* Check if we have connection information */
512     if (ConnectionInformation)
513     {
514         _SEH2_TRY
515         {
516             /* Copy it in */
517             RtlCopyMemory(ConnectMessage + 1,
518                           ConnectionInformation,
519                           ConnectionInfoLength);
520         }
521         _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
522         {
523             DPRINT1("Exception 0x%lx when copying connection info to user mode\n",
524                     _SEH2_GetExceptionCode());
525 
526             /* Cleanup and return the exception code */
527 
528             /* Free the message we have */
529             LpcpFreeToPortZone(Message, 0);
530 
531             /* Dereference other objects */
532             if (SectionToMap) ObDereferenceObject(SectionToMap);
533             ObDereferenceObject(ClientPort);
534 
535             /* Return status */
536             _SEH2_YIELD(return _SEH2_GetExceptionCode());
537         }
538         _SEH2_END;
539     }
540 
541     /* Reset the status code */
542     Status = STATUS_SUCCESS;
543 
544     /* Acquire the port lock */
545     KeAcquireGuardedMutex(&LpcpLock);
546 
547     /* Check if someone already deleted the port name */
548     if (Port->Flags & LPCP_NAME_DELETED)
549     {
550         /* Fail the request */
551         Status = STATUS_OBJECT_NAME_NOT_FOUND;
552     }
553     else
554     {
555         /* Associate no thread yet */
556         Message->RepliedToThread = NULL;
557 
558         /* Generate the Message ID and set it */
559         Message->Request.MessageId =  LpcpNextMessageId++;
560         if (!LpcpNextMessageId) LpcpNextMessageId = 1;
561         Thread->LpcReplyMessageId = Message->Request.MessageId;
562 
563         /* Insert the message into the queue and thread chain */
564         InsertTailList(&Port->MsgQueue.ReceiveHead, &Message->Entry);
565         InsertTailList(&Port->LpcReplyChainHead, &Thread->LpcReplyChain);
566         Thread->LpcReplyMessage = Message;
567 
568         /* Now we can finally reference the client port and link it */
569         ObReferenceObject(ClientPort);
570         ConnectMessage->ClientPort = ClientPort;
571 
572         /* Enter a critical region */
573         KeEnterCriticalRegion();
574     }
575 
576     /* Add another reference to the port */
577     ObReferenceObject(Port);
578 
579     /* Release the lock */
580     KeReleaseGuardedMutex(&LpcpLock);
581 
582     /* Check for success */
583     if (NT_SUCCESS(Status))
584     {
585         LPCTRACE(LPC_CONNECT_DEBUG,
586                  "Messages: %p/%p. Ports: %p/%p. Status: %lx\n",
587                  Message,
588                  ConnectMessage,
589                  Port,
590                  ClientPort,
591                  Status);
592 
593         /* If this is a waitable port, set the event */
594         if (Port->Flags & LPCP_WAITABLE_PORT)
595             KeSetEvent(&Port->WaitEvent, 1, FALSE);
596 
597         /* Release the queue semaphore and leave the critical region */
598         LpcpCompleteWait(Port->MsgQueue.Semaphore);
599         KeLeaveCriticalRegion();
600 
601         /* Now wait for a reply and set 'Status' */
602         LpcpConnectWait(&Thread->LpcReplySemaphore, PreviousMode);
603     }
604 
605     /* Now, always free the connection message */
606     SectionToMap = LpcpFreeConMsg(&Message, &ConnectMessage, Thread);
607 
608     /* Check for failure */
609     if (!NT_SUCCESS(Status))
610     {
611         /* Check if the semaphore got signaled in the meantime */
612         if (KeReadStateSemaphore(&Thread->LpcReplySemaphore))
613         {
614             /* Wait on it */
615             KeWaitForSingleObject(&Thread->LpcReplySemaphore,
616                                   WrExecutive,
617                                   KernelMode,
618                                   FALSE,
619                                   NULL);
620         }
621 
622         goto Failure;
623     }
624 
625     /* Check if we got a message back */
626     if (Message)
627     {
628         /* Check for new return length */
629         if ((Message->Request.u1.s1.DataLength -
630              sizeof(LPCP_CONNECTION_MESSAGE)) < ConnectionInfoLength)
631         {
632             /* Set new normalized connection length */
633             ConnectionInfoLength = Message->Request.u1.s1.DataLength -
634                                    sizeof(LPCP_CONNECTION_MESSAGE);
635         }
636 
637         /* Check if the caller had connection information */
638         if (ConnectionInformation)
639         {
640             _SEH2_TRY
641             {
642                 /* Return the connection information length if needed */
643                 if (ConnectionInformationLength)
644                     *ConnectionInformationLength = ConnectionInfoLength;
645 
646                 /* Return the connection information */
647                 RtlCopyMemory(ConnectionInformation,
648                               ConnectMessage + 1,
649                               ConnectionInfoLength);
650             }
651             _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
652             {
653                 /* Cleanup and return the exception code */
654                 Status = _SEH2_GetExceptionCode();
655                 _SEH2_YIELD(goto Failure);
656             }
657             _SEH2_END;
658         }
659 
660         /* Make sure we had a connected port */
661         if (ClientPort->ConnectedPort)
662         {
663             /* Get the message length before the port might get killed */
664             PortMessageLength = Port->MaxMessageLength;
665 
666             /* Insert the client port */
667             Status = ObInsertObject(ClientPort,
668                                     NULL,
669                                     PORT_ALL_ACCESS,
670                                     0,
671                                     NULL,
672                                     &Handle);
673             if (NT_SUCCESS(Status))
674             {
675                 LPCTRACE(LPC_CONNECT_DEBUG,
676                          "Handle: %p. Length: %lx\n",
677                          Handle,
678                          PortMessageLength);
679 
680                 _SEH2_TRY
681                 {
682                     /* Return the handle */
683                     *PortHandle = Handle;
684 
685                     /* Check if maximum length was requested */
686                     if (MaxMessageLength)
687                         *MaxMessageLength = PortMessageLength;
688 
689                     /* Check if we had a client view */
690                     if (ClientView)
691                     {
692                         /* Copy it back */
693                         RtlCopyMemory(ClientView,
694                                       &ConnectMessage->ClientView,
695                                       sizeof(*ClientView));
696                     }
697 
698                     /* Check if we had a server view */
699                     if (ServerView)
700                     {
701                         /* Copy it back */
702                         RtlCopyMemory(ServerView,
703                                       &ConnectMessage->ServerView,
704                                       sizeof(*ServerView));
705                     }
706                 }
707                 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
708                 {
709                     /* An exception happened, close the opened handle */
710                     ObCloseHandle(Handle, PreviousMode);
711                     Status = _SEH2_GetExceptionCode();
712                 }
713                 _SEH2_END;
714             }
715         }
716         else
717         {
718             /* No connection port, we failed */
719             if (SectionToMap) ObDereferenceObject(SectionToMap);
720 
721             /* Acquire the lock */
722             KeAcquireGuardedMutex(&LpcpLock);
723 
724             /* Check if it's because the name got deleted */
725             if (!(ClientPort->ConnectionPort) ||
726                 (Port->Flags & LPCP_NAME_DELETED))
727             {
728                 /* Set the correct status */
729                 Status = STATUS_OBJECT_NAME_NOT_FOUND;
730             }
731             else
732             {
733                 /* Otherwise, the caller refused us */
734                 Status = STATUS_PORT_CONNECTION_REFUSED;
735             }
736 
737             /* Release the lock */
738             KeReleaseGuardedMutex(&LpcpLock);
739 
740             /* Kill the port */
741             ObDereferenceObject(ClientPort);
742         }
743 
744         /* Free the message */
745         LpcpFreeToPortZone(Message, 0);
746     }
747     else
748     {
749         /* No reply message, fail */
750         Status = STATUS_PORT_CONNECTION_REFUSED;
751         goto Failure;
752     }
753 
754     ObDereferenceObject(Port);
755 
756     /* Return status */
757     return Status;
758 
759 Failure:
760     /* Check if we had a message and free it */
761     if (Message) LpcpFreeToPortZone(Message, 0);
762 
763     /* Dereference other objects */
764     if (SectionToMap) ObDereferenceObject(SectionToMap);
765     ObDereferenceObject(ClientPort);
766     ObDereferenceObject(Port);
767 
768     /* Return status */
769     return Status;
770 }
771 
772 /*
773  * @implemented
774  */
775 NTSTATUS
776 NTAPI
777 NtConnectPort(OUT PHANDLE PortHandle,
778               IN PUNICODE_STRING PortName,
779               IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,
780               IN OUT PPORT_VIEW ClientView OPTIONAL,
781               IN OUT PREMOTE_PORT_VIEW ServerView OPTIONAL,
782               OUT PULONG MaxMessageLength OPTIONAL,
783               IN OUT PVOID ConnectionInformation OPTIONAL,
784               IN OUT PULONG ConnectionInformationLength OPTIONAL)
785 {
786     /* Call the newer API */
787     return NtSecureConnectPort(PortHandle,
788                                PortName,
789                                SecurityQos,
790                                ClientView,
791                                NULL,
792                                ServerView,
793                                MaxMessageLength,
794                                ConnectionInformation,
795                                ConnectionInformationLength);
796 }
797 
798 /* EOF */
799