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)
9 /* INCLUDES ******************************************************************/
14 #include <internal/debug.h>
16 /* PRIVATE FUNCTIONS *********************************************************/
20 LpcpFreeConMsg(IN OUT PLPCP_MESSAGE
*Message
,
21 IN OUT PLPCP_CONNECTION_MESSAGE
*ConnectMessage
,
22 IN PETHREAD CurrentThread
)
26 /* Acquire the LPC lock */
27 KeAcquireGuardedMutex(&LpcpLock
);
29 /* Check if the reply chain is not empty */
30 if (!IsListEmpty(&CurrentThread
->LpcReplyChain
))
32 /* Remove this entry and re-initialize it */
33 RemoveEntryList(&CurrentThread
->LpcReplyChain
);
34 InitializeListHead(&CurrentThread
->LpcReplyChain
);
37 /* Check if there's a reply message */
38 if (CurrentThread
->LpcReplyMessage
)
41 *Message
= CurrentThread
->LpcReplyMessage
;
43 /* Clear message data */
44 CurrentThread
->LpcReceivedMessageId
= 0;
45 CurrentThread
->LpcReplyMessage
= NULL
;
47 /* Get the connection message and clear the section */
48 *ConnectMessage
= (PLPCP_CONNECTION_MESSAGE
)(*Message
+ 1);
49 SectionToMap
= (*ConnectMessage
)->SectionToMap
;
50 (*ConnectMessage
)->SectionToMap
= NULL
;
54 /* No message to return */
59 /* Release the lock and return the section */
60 KeReleaseGuardedMutex(&LpcpLock
);
64 /* PUBLIC FUNCTIONS **********************************************************/
71 NtSecureConnectPort(OUT PHANDLE PortHandle
,
72 IN PUNICODE_STRING PortName
,
73 IN PSECURITY_QUALITY_OF_SERVICE Qos
,
74 IN OUT PPORT_VIEW ClientView OPTIONAL
,
75 IN PSID ServerSid OPTIONAL
,
76 IN OUT PREMOTE_PORT_VIEW ServerView OPTIONAL
,
77 OUT PULONG MaxMessageLength OPTIONAL
,
78 IN OUT PVOID ConnectionInformation OPTIONAL
,
79 IN OUT PULONG ConnectionInformationLength OPTIONAL
)
81 ULONG ConnectionInfoLength
= 0;
82 PLPCP_PORT_OBJECT Port
, ClientPort
;
83 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
84 NTSTATUS Status
= STATUS_SUCCESS
;
87 PLPCP_MESSAGE Message
;
88 PLPCP_CONNECTION_MESSAGE ConnectMessage
;
89 PETHREAD Thread
= PsGetCurrentThread();
90 ULONG PortMessageLength
;
91 LARGE_INTEGER SectionOffset
;
93 PTOKEN_USER TokenUserInfo
;
95 LPCTRACE(LPC_CONNECT_DEBUG
,
96 "Name: %wZ. Qos: %p. Views: %p/%p. Sid: %p\n",
103 /* Validate client view */
104 if ((ClientView
) && (ClientView
->Length
!= sizeof(PORT_VIEW
)))
107 return STATUS_INVALID_PARAMETER
;
110 /* Validate server view */
111 if ((ServerView
) && (ServerView
->Length
!= sizeof(REMOTE_PORT_VIEW
)))
114 return STATUS_INVALID_PARAMETER
;
117 /* Check if caller sent connection information length */
118 if (ConnectionInformationLength
)
120 /* Retrieve the input length */
121 ConnectionInfoLength
= *ConnectionInformationLength
;
125 Status
= ObReferenceObjectByName(PortName
,
133 if (!NT_SUCCESS(Status
)) return Status
;
135 /* This has to be a connection port */
136 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) != LPCP_CONNECTION_PORT
)
138 /* It isn't, so fail */
139 ObDereferenceObject(Port
);
140 return STATUS_INVALID_PORT_HANDLE
;
143 /* Check if we have a SID */
146 /* Make sure that we have a server */
147 if (Port
->ServerProcess
)
149 /* Get its token and query user information */
150 Token
= PsReferencePrimaryToken(Port
->ServerProcess
);
151 //Status = SeQueryInformationToken(Token, TokenUser, (PVOID*)&TokenUserInfo);
152 // FIXME: Need SeQueryInformationToken
153 Status
= STATUS_SUCCESS
;
154 TokenUserInfo
= ExAllocatePool(PagedPool
, sizeof(TOKEN_USER
));
155 TokenUserInfo
->User
.Sid
= ServerSid
;
156 PsDereferencePrimaryToken(Token
);
158 /* Check for success */
159 if (NT_SUCCESS(Status
))
161 /* Compare the SIDs */
162 if (!RtlEqualSid(ServerSid
, TokenUserInfo
->User
.Sid
))
165 Status
= STATUS_SERVER_SID_MISMATCH
;
168 /* Free token information */
169 ExFreePool(TokenUserInfo
);
175 Status
= STATUS_SERVER_SID_MISMATCH
;
178 /* Check if SID failed */
179 if (!NT_SUCCESS(Status
))
182 ObDereferenceObject(Port
);
187 /* Create the client port */
188 Status
= ObCreateObject(PreviousMode
,
193 sizeof(LPCP_PORT_OBJECT
),
196 (PVOID
*)&ClientPort
);
197 if (!NT_SUCCESS(Status
))
199 /* Failed, dereference the server port and return */
200 ObDereferenceObject(Port
);
204 /* Setup the client port */
205 RtlZeroMemory(ClientPort
, sizeof(LPCP_PORT_OBJECT
));
206 ClientPort
->Flags
= LPCP_CLIENT_PORT
;
207 ClientPort
->ConnectionPort
= Port
;
208 ClientPort
->MaxMessageLength
= Port
->MaxMessageLength
;
209 ClientPort
->SecurityQos
= *Qos
;
210 InitializeListHead(&ClientPort
->LpcReplyChainHead
);
211 InitializeListHead(&ClientPort
->LpcDataInfoChainHead
);
213 /* Check if we have dynamic security */
214 if (Qos
->ContextTrackingMode
== SECURITY_DYNAMIC_TRACKING
)
217 ClientPort
->Flags
|= LPCP_SECURITY_DYNAMIC
;
221 /* Create our own client security */
222 Status
= SeCreateClientSecurity(Thread
,
225 &ClientPort
->StaticSecurity
);
226 if (!NT_SUCCESS(Status
))
228 /* Security failed, dereference and return */
229 ObDereferenceObject(ClientPort
);
234 /* Initialize the port queue */
235 Status
= LpcpInitializePortQueue(ClientPort
);
236 if (!NT_SUCCESS(Status
))
239 ObDereferenceObject(ClientPort
);
243 /* Check if we have a client view */
246 /* Get the section handle */
247 Status
= ObReferenceObjectByHandle(ClientView
->SectionHandle
,
252 (PVOID
*)&SectionToMap
,
254 if (!NT_SUCCESS(Status
))
257 ObDereferenceObject(Port
);
261 /* Set the section offset */
262 SectionOffset
.QuadPart
= ClientView
->SectionOffset
;
265 Status
= MmMapViewOfSection(SectionToMap
,
266 PsGetCurrentProcess(),
267 &Port
->ClientSectionBase
,
271 &ClientView
->ViewSize
,
276 /* Update the offset */
277 ClientView
->SectionOffset
= SectionOffset
.LowPart
;
279 /* Check for failure */
280 if (!NT_SUCCESS(Status
))
283 ObDereferenceObject(SectionToMap
);
284 ObDereferenceObject(Port
);
288 /* Update the base */
289 ClientView
->ViewBase
= Port
->ClientSectionBase
;
297 /* Normalize connection information */
298 if (ConnectionInfoLength
> Port
->MaxConnectionInfoLength
)
300 /* Use the port's maximum allowed value */
301 ConnectionInfoLength
= Port
->MaxConnectionInfoLength
;
304 /* Allocate a message from the port zone */
305 Message
= LpcpAllocateFromPortZone();
308 /* Fail if we couldn't allocate a message */
309 if (SectionToMap
) ObDereferenceObject(SectionToMap
);
310 ObDereferenceObject(ClientPort
);
311 return STATUS_NO_MEMORY
;
314 /* Set pointer to the connection message and fill in the CID */
315 ConnectMessage
= (PLPCP_CONNECTION_MESSAGE
)(Message
+ 1);
316 Message
->Request
.ClientId
= Thread
->Cid
;
318 /* Check if we have a client view */
321 /* Set the view size */
322 Message
->Request
.ClientViewSize
= ClientView
->ViewSize
;
324 /* Copy the client view and clear the server view */
325 RtlMoveMemory(&ConnectMessage
->ClientView
,
328 RtlZeroMemory(&ConnectMessage
->ServerView
, sizeof(REMOTE_PORT_VIEW
));
332 /* Set the size to 0 and clear the connect message */
333 Message
->Request
.ClientViewSize
= 0;
334 RtlZeroMemory(ConnectMessage
, sizeof(LPCP_CONNECTION_MESSAGE
));
337 /* Set the section and client port. Port is NULL for now */
338 ConnectMessage
->ClientPort
= NULL
;
339 ConnectMessage
->SectionToMap
= SectionToMap
;
341 /* Set the data for the connection request message */
342 Message
->Request
.u1
.s1
.DataLength
= sizeof(LPCP_CONNECTION_MESSAGE
) +
343 ConnectionInfoLength
;
344 Message
->Request
.u1
.s1
.TotalLength
= sizeof(LPCP_MESSAGE
) +
345 Message
->Request
.u1
.s1
.DataLength
;
346 Message
->Request
.u2
.s2
.Type
= LPC_CONNECTION_REQUEST
;
348 /* Check if we have connection information */
349 if (ConnectionInformation
)
352 RtlMoveMemory(ConnectMessage
+ 1,
353 ConnectionInformation
,
354 ConnectionInfoLength
);
357 /* Acquire the port lock */
358 KeAcquireGuardedMutex(&LpcpLock
);
360 /* Check if someone already deleted the port name */
361 if (Port
->Flags
& LPCP_NAME_DELETED
)
363 /* Fail the request */
364 KeReleaseGuardedMutex(&LpcpLock
);
365 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
369 /* Associate no thread yet */
370 Message
->RepliedToThread
= NULL
;
372 /* Generate the Message ID and set it */
373 Message
->Request
.MessageId
= LpcpNextMessageId
++;
374 if (!LpcpNextMessageId
) LpcpNextMessageId
= 1;
375 Thread
->LpcReplyMessageId
= Message
->Request
.MessageId
;
377 /* Insert the message into the queue and thread chain */
378 InsertTailList(&Port
->MsgQueue
.ReceiveHead
, &Message
->Entry
);
379 InsertTailList(&Port
->LpcReplyChainHead
, &Thread
->LpcReplyChain
);
380 Thread
->LpcReplyMessage
= Message
;
382 /* Now we can finally reference the client port and link it*/
383 ObReferenceObject(ClientPort
);
384 ConnectMessage
->ClientPort
= ClientPort
;
386 /* Release the lock */
387 KeReleaseGuardedMutex(&LpcpLock
);
388 LPCTRACE(LPC_CONNECT_DEBUG
,
389 "Messages: %p/%p. Ports: %p/%p. Status: %lx\n",
396 /* If this is a waitable port, set the event */
397 if (Port
->Flags
& LPCP_WAITABLE_PORT
) KeSetEvent(&Port
->WaitEvent
,
401 /* Release the queue semaphore */
402 LpcpCompleteWait(Port
->MsgQueue
.Semaphore
);
404 /* Now wait for a reply */
405 LpcpConnectWait(&Thread
->LpcReplySemaphore
, PreviousMode
);
407 /* Check if our wait ended in success */
408 if (Status
!= STATUS_SUCCESS
) goto Cleanup
;
410 /* Free the connection message */
411 SectionToMap
= LpcpFreeConMsg(&Message
, &ConnectMessage
, Thread
);
413 /* Check if we got a message back */
416 /* Check for new return length */
417 if ((Message
->Request
.u1
.s1
.DataLength
-
418 sizeof(LPCP_CONNECTION_MESSAGE
)) < ConnectionInfoLength
)
420 /* Set new normalized connection length */
421 ConnectionInfoLength
= Message
->Request
.u1
.s1
.DataLength
-
422 sizeof(LPCP_CONNECTION_MESSAGE
);
425 /* Check if we had connection information */
426 if (ConnectionInformation
)
428 /* Check if we had a length pointer */
429 if (ConnectionInformationLength
)
431 /* Return the length */
432 *ConnectionInformationLength
= ConnectionInfoLength
;
435 /* Return the connection information */
436 RtlMoveMemory(ConnectionInformation
,
438 ConnectionInfoLength
);
441 /* Make sure we had a connected port */
442 if (ClientPort
->ConnectedPort
)
444 /* Get the message length before the port might get killed */
445 PortMessageLength
= Port
->MaxMessageLength
;
447 /* Insert the client port */
448 Status
= ObInsertObject(ClientPort
,
454 if (NT_SUCCESS(Status
))
456 /* Return the handle */
457 *PortHandle
= Handle
;
458 LPCTRACE(LPC_CONNECT_DEBUG
,
459 "Handle: %lx. Length: %lx\n",
463 /* Check if maximum length was requested */
464 if (MaxMessageLength
) *MaxMessageLength
= PortMessageLength
;
466 /* Check if we had a client view */
470 RtlMoveMemory(ClientView
,
471 &ConnectMessage
->ClientView
,
475 /* Check if we had a server view */
479 RtlMoveMemory(ServerView
,
480 &ConnectMessage
->ServerView
,
481 sizeof(REMOTE_PORT_VIEW
));
487 /* No connection port, we failed */
488 if (SectionToMap
) ObDereferenceObject(SectionToMap
);
490 /* Check if it's because the name got deleted */
491 if (Port
->Flags
& LPCP_NAME_DELETED
)
493 /* Set the correct status */
494 Status
= STATUS_OBJECT_NAME_NOT_FOUND
;
498 /* Otherwise, the caller refused us */
499 Status
= STATUS_PORT_CONNECTION_REFUSED
;
503 ObDereferenceObject(ClientPort
);
506 /* Free the message */
507 LpcpFreeToPortZone(Message
, FALSE
);
511 /* No reply message, fail */
512 if (SectionToMap
) ObDereferenceObject(SectionToMap
);
513 ObDereferenceObject(ClientPort
);
514 return STATUS_PORT_CONNECTION_REFUSED
;
517 /* We failed, free the message */
518 SectionToMap
= LpcpFreeConMsg(&Message
, &ConnectMessage
, Thread
);
520 /* Check if the semaphore got signaled */
521 if (KeReadStateSemaphore(&Thread
->LpcReplySemaphore
))
524 KeWaitForSingleObject(&Thread
->LpcReplySemaphore
,
531 /* Check if we had a message and free it */
532 if (Message
) LpcpFreeToPortZone(Message
, FALSE
);
534 /* Dereference other objects */
535 if (SectionToMap
) ObDereferenceObject(SectionToMap
);
536 ObDereferenceObject(ClientPort
);
547 NtConnectPort(OUT PHANDLE PortHandle
,
548 IN PUNICODE_STRING PortName
,
549 IN PSECURITY_QUALITY_OF_SERVICE Qos
,
550 IN PPORT_VIEW ClientView
,
551 IN PREMOTE_PORT_VIEW ServerView
,
552 OUT PULONG MaxMessageLength
,
553 IN PVOID ConnectionInformation
,
554 OUT PULONG ConnectionInformationLength
)
556 /* Call the newer API */
557 return NtSecureConnectPort(PortHandle
,
564 ConnectionInformation
,
565 ConnectionInformationLength
);