2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/lpc/port.c
5 * PURPOSE: Local Procedure Call: Port Management
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
9 /* INCLUDES ******************************************************************/
15 /* GLOBALS *******************************************************************/
17 POBJECT_TYPE LpcPortObjectType
, LpcWaitablePortObjectType
;
18 ULONG LpcpMaxMessageSize
;
19 PAGED_LOOKASIDE_LIST LpcpMessagesLookaside
;
20 KGUARDED_MUTEX LpcpLock
;
21 ULONG LpcpTraceLevel
= 0;
22 ULONG LpcpNextMessageId
= 1, LpcpNextCallbackId
= 1;
24 static GENERIC_MAPPING LpcpPortMapping
=
26 READ_CONTROL
| PORT_CONNECT
,
27 DELETE
| PORT_CONNECT
,
32 /* PRIVATE FUNCTIONS *********************************************************/
39 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer
;
42 /* Setup the LPC Lock */
43 KeInitializeGuardedMutex(&LpcpLock
);
45 /* Create the Port Object Type */
46 RtlZeroMemory(&ObjectTypeInitializer
, sizeof(ObjectTypeInitializer
));
47 RtlInitUnicodeString(&Name
, L
"Port");
48 ObjectTypeInitializer
.Length
= sizeof(ObjectTypeInitializer
);
49 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
= sizeof(LPCP_NONPAGED_PORT_QUEUE
);
50 ObjectTypeInitializer
.DefaultPagedPoolCharge
= FIELD_OFFSET(LPCP_PORT_OBJECT
, WaitEvent
);
51 ObjectTypeInitializer
.GenericMapping
= LpcpPortMapping
;
52 ObjectTypeInitializer
.PoolType
= PagedPool
;
53 ObjectTypeInitializer
.UseDefaultObject
= TRUE
;
54 ObjectTypeInitializer
.CloseProcedure
= LpcpClosePort
;
55 ObjectTypeInitializer
.DeleteProcedure
= LpcpDeletePort
;
56 ObjectTypeInitializer
.ValidAccessMask
= PORT_ALL_ACCESS
;
57 ObjectTypeInitializer
.InvalidAttributes
= OBJ_VALID_ATTRIBUTES
& ~OBJ_CASE_INSENSITIVE
;
58 ObCreateObjectType(&Name
,
59 &ObjectTypeInitializer
,
63 /* Create the Waitable Port Object Type */
64 RtlInitUnicodeString(&Name
, L
"WaitablePort");
65 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
66 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
+= sizeof(LPCP_PORT_OBJECT
);
67 ObjectTypeInitializer
.DefaultPagedPoolCharge
= 0;
68 ObjectTypeInitializer
.UseDefaultObject
= FALSE
;
69 ObCreateObjectType(&Name
,
70 &ObjectTypeInitializer
,
72 &LpcWaitablePortObjectType
);
74 /* Allocate the LPC lookaside list */
75 LpcpMaxMessageSize
= LPCP_MAX_MESSAGE_SIZE
;
76 ExInitializePagedLookasideList(&LpcpMessagesLookaside
,
90 LpcpValidateClientPort(
91 PETHREAD ClientThread
,
92 PLPCP_PORT_OBJECT Port
)
94 PLPCP_PORT_OBJECT ThreadPort
;
96 /* Get the thread's port */
97 ThreadPort
= LpcpGetPortFromThread(ClientThread
);
98 if (ThreadPort
== NULL
)
103 /* Check if the port matches directly */
104 if ((Port
== ThreadPort
) ||
105 (Port
== ThreadPort
->ConnectionPort
) ||
106 (Port
== ThreadPort
->ConnectedPort
))
111 /* Check if this is a communication port and the connection port matches */
112 if (((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_COMMUNICATION_PORT
) &&
113 (Port
->ConnectionPort
== ThreadPort
))
122 /* PUBLIC FUNCTIONS **********************************************************/
126 NtImpersonateClientOfPort(IN HANDLE PortHandle
,
127 IN PPORT_MESSAGE ClientMessage
)
130 KPROCESSOR_MODE PreviousMode
= KeGetPreviousMode();
133 PLPCP_PORT_OBJECT Port
= NULL
, ConnectedPort
= NULL
;
134 PETHREAD ClientThread
= NULL
;
135 SECURITY_CLIENT_CONTEXT ClientContext
;
139 /* Check if the call comes from user mode */
140 if (PreviousMode
!= KernelMode
)
144 ProbeForRead(ClientMessage
, sizeof(*ClientMessage
), sizeof(PVOID
));
145 ClientId
= ((volatile PORT_MESSAGE
*)ClientMessage
)->ClientId
;
146 MessageId
= ((volatile PORT_MESSAGE
*)ClientMessage
)->MessageId
;
148 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
150 _SEH2_YIELD(return _SEH2_GetExceptionCode());
156 ClientId
= ClientMessage
->ClientId
;
157 MessageId
= ClientMessage
->MessageId
;
160 /* Reference the port handle */
161 Status
= ObReferenceObjectByHandle(PortHandle
,
167 if (!NT_SUCCESS(Status
))
169 DPRINT1("Failed to reference port handle: 0x%ls\n", Status
);
173 /* Make sure this is a connection port */
174 if ((Port
->Flags
& LPCP_PORT_TYPE_MASK
) != LPCP_COMMUNICATION_PORT
)
177 DPRINT1("Port is not a communication port\n");
178 Status
= STATUS_INVALID_PORT_HANDLE
;
182 /* Look up the client thread */
183 Status
= PsLookupProcessThreadByCid(&ClientId
, NULL
, &ClientThread
);
184 if (!NT_SUCCESS(Status
))
186 DPRINT1("Failed to lookup client thread: 0x%ls\n", Status
);
190 /* Acquire the lock */
191 KeAcquireGuardedMutex(&LpcpLock
);
193 /* Get the connected port and try to reference it */
194 ConnectedPort
= Port
->ConnectedPort
;
195 if ((ConnectedPort
== NULL
) || !ObReferenceObjectSafe(ConnectedPort
))
197 DPRINT1("Failed to reference the connected port\n");
198 ConnectedPort
= NULL
;
199 Status
= STATUS_PORT_DISCONNECTED
;
200 goto CleanupWithLock
;
203 /* Check for no-impersonation flag */
204 if ((ULONG_PTR
)ClientThread
->LpcReplyMessage
& LPCP_THREAD_FLAG_NO_IMPERSONATION
)
206 DPRINT1("Reply message has no impersonation flag set\n");
207 Status
= STATUS_ACCESS_DENIED
;
208 goto CleanupWithLock
;
211 /* Check for message id mismatch */
212 if ((ClientThread
->LpcReplyMessageId
!= MessageId
) || (MessageId
== 0))
214 DPRINT1("LpcReplyMessageId mismatch: 0x%lx/0x%lx.\n",
215 ClientThread
->LpcReplyMessageId
, MessageId
);
216 Status
= STATUS_REPLY_MESSAGE_MISMATCH
;
217 goto CleanupWithLock
;
220 /* Validate the port */
221 if (!LpcpValidateClientPort(ClientThread
, Port
))
223 DPRINT1("LpcpValidateClientPort failed\n");
224 Status
= STATUS_REPLY_MESSAGE_MISMATCH
;
225 goto CleanupWithLock
;
228 /* Release the lock */
229 KeReleaseGuardedMutex(&LpcpLock
);
231 /* Check if security is static */
232 if (!(ConnectedPort
->Flags
& LPCP_SECURITY_DYNAMIC
))
234 /* Use the static security for impersonation */
235 Status
= SeImpersonateClientEx(&ConnectedPort
->StaticSecurity
, NULL
);
239 /* Create new dynamic security */
240 Status
= SeCreateClientSecurity(ClientThread
,
241 &ConnectedPort
->SecurityQos
,
244 if (!NT_SUCCESS(Status
))
246 DPRINT1("SeCreateClientSecurity failed\n");
250 /* Use dynamic security for impersonation */
251 Status
= SeImpersonateClientEx(&ClientContext
, NULL
);
253 /* Get rid of the security context */
254 SeDeleteClientSecurity(&ClientContext
);
258 if (ConnectedPort
!= NULL
)
259 ObDereferenceObject(ConnectedPort
);
261 if (ClientThread
!= NULL
)
262 ObDereferenceObject(ClientThread
);
264 ObDereferenceObject(Port
);
270 /* Release the lock */
271 KeReleaseGuardedMutex(&LpcpLock
);
277 NtQueryPortInformationProcess(VOID
)
279 /* This is all this function does */
280 return STATUS_UNSUCCESSFUL
;
285 NtQueryInformationPort(IN HANDLE PortHandle
,
286 IN PORT_INFORMATION_CLASS PortInformationClass
,
287 OUT PVOID PortInformation
,
288 IN ULONG PortInformationLength
,
289 OUT PULONG ReturnLength
)
292 return STATUS_NOT_IMPLEMENTED
;