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
LpcpFreeConMsg(IN OUT PLPCP_MESSAGE * Message,IN OUT PLPCP_CONNECTION_MESSAGE * ConnectMessage,IN PETHREAD CurrentThread)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
NtSecureConnectPort(OUT PHANDLE PortHandle,IN PUNICODE_STRING PortName,IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,IN OUT PPORT_VIEW ClientView OPTIONAL,IN PSID ServerSid OPTIONAL,IN OUT PREMOTE_PORT_VIEW ServerView OPTIONAL,OUT PULONG MaxMessageLength OPTIONAL,IN OUT PVOID ConnectionInformation OPTIONAL,IN OUT PULONG ConnectionInformationLength OPTIONAL)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
NtConnectPort(OUT PHANDLE PortHandle,IN PUNICODE_STRING PortName,IN PSECURITY_QUALITY_OF_SERVICE SecurityQos,IN OUT PPORT_VIEW ClientView OPTIONAL,IN OUT PREMOTE_PORT_VIEW ServerView OPTIONAL,OUT PULONG MaxMessageLength OPTIONAL,IN OUT PVOID ConnectionInformation OPTIONAL,IN OUT PULONG ConnectionInformationLength OPTIONAL)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