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