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 RtlInitUnicodeString(&Name
, L
"WaitablePort");
64 ObjectTypeInitializer
.PoolType
= NonPagedPool
;
65 ObjectTypeInitializer
.DefaultNonPagedPoolCharge
+= sizeof(LPCP_PORT_OBJECT
);
66 ObjectTypeInitializer
.DefaultPagedPoolCharge
= 0;
67 ObjectTypeInitializer
.UseDefaultObject
= FALSE
;
68 ObCreateObjectType(&Name
,
69 &ObjectTypeInitializer
,
71 &LpcWaitablePortObjectType
);
73 /* Allocate the LPC lookaside list */
74 LpcpMaxMessageSize
= LPCP_MAX_MESSAGE_SIZE
;
75 ExInitializePagedLookasideList(&LpcpMessagesLookaside
,
89 LpcpValidateClientPort(
90 PETHREAD ClientThread
,
91 PLPCP_PORT_OBJECT Port
)
93 PLPCP_PORT_OBJECT ThreadPort
;
95 /* Get the thread's port */
96 ThreadPort
= LpcpGetPortFromThread(ClientThread
);
97 if (ThreadPort
== NULL
)
102 /* Check if the port matches directly */
103 if ((Port
== ThreadPort
) ||
104 (Port
== ThreadPort
->ConnectionPort
) ||
105 (Port
== ThreadPort
->ConnectedPort
))
110 /* Check if this is a communication port and the connection port matches */
111 if (((Port
->Flags
& LPCP_PORT_TYPE_MASK
) == LPCP_COMMUNICATION_PORT
) &&
112 (Port
->ConnectionPort
== ThreadPort
))
121 /* PUBLIC FUNCTIONS **********************************************************/
125 NtImpersonateClientOfPort(IN HANDLE PortHandle
,
126 IN PPORT_MESSAGE ClientMessage
)
128 KPROCESSOR_MODE PreviousMode
;
131 PLPCP_PORT_OBJECT Port
= NULL
, ConnectedPort
= NULL
;
132 PETHREAD ClientThread
= NULL
;
133 SECURITY_CLIENT_CONTEXT ClientContext
;
137 /* Check the previous mode */
138 PreviousMode
= ExGetPreviousMode();
139 if (PreviousMode
== KernelMode
)
141 ClientId
= ClientMessage
->ClientId
;
142 MessageId
= ClientMessage
->MessageId
;
148 ProbeForRead(ClientMessage
, sizeof(*ClientMessage
), sizeof(PVOID
));
149 ClientId
= ClientMessage
->ClientId
;
150 MessageId
= ClientMessage
->MessageId
;
152 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER
)
154 DPRINT1("Got exception!\n");
155 return _SEH2_GetExceptionCode();
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
) ||
196 !ObReferenceObjectSafe(ConnectedPort
))
198 DPRINT1("Failed to reference the connected port\n");
199 ConnectedPort
= NULL
;
200 Status
= STATUS_PORT_DISCONNECTED
;
201 goto CleanupWithLock
;
204 /* Check for no-impersonation flag */
205 if ((ULONG_PTR
)ClientThread
->LpcReplyMessage
& LPCP_THREAD_FLAG_NO_IMPERSONATION
)
207 DPRINT1("Reply message has no impersonation flag set\n");
208 Status
= STATUS_ACCESS_DENIED
;
209 goto CleanupWithLock
;
212 /* Check for message id mismatch */
213 if ((ClientThread
->LpcReplyMessageId
!= MessageId
) || (MessageId
== 0))
215 DPRINT1("LpcReplyMessageId mismatch: 0x%lx/0x%lx.\n",
216 ClientThread
->LpcReplyMessageId
, MessageId
);
217 Status
= STATUS_REPLY_MESSAGE_MISMATCH
;
218 goto CleanupWithLock
;
221 /* Validate the port */
222 if (!LpcpValidateClientPort(ClientThread
, Port
))
224 DPRINT1("LpcpValidateClientPort failed\n");
225 Status
= STATUS_REPLY_MESSAGE_MISMATCH
;
226 goto CleanupWithLock
;
229 /* Release the lock */
230 KeReleaseGuardedMutex(&LpcpLock
);
232 /* Check if security is static */
233 if (!(ConnectedPort
->Flags
& LPCP_SECURITY_DYNAMIC
))
235 /* Use the static security for impersonation */
236 Status
= SeImpersonateClientEx(&ConnectedPort
->StaticSecurity
, NULL
);
240 /* Create new dynamic security */
241 Status
= SeCreateClientSecurity(ClientThread
,
242 &ConnectedPort
->SecurityQos
,
245 if (!NT_SUCCESS(Status
))
247 DPRINT1("SeCreateClientSecurity failed\n");
251 /* Use dynamic security for impersonation */
252 Status
= SeImpersonateClientEx(&ClientContext
, NULL
);
254 /* Get rid of the security context */
255 SeDeleteClientSecurity(&ClientContext
);
261 /* Release the lock */
262 KeReleaseGuardedMutex(&LpcpLock
);
266 if (ConnectedPort
!= NULL
)
267 ObDereferenceObject(ConnectedPort
);
269 if (ClientThread
!= NULL
)
270 ObDereferenceObject(ClientThread
);
272 ObDereferenceObject(Port
);
279 NtQueryPortInformationProcess(VOID
)
281 /* This is all this function does */
282 return STATUS_UNSUCCESSFUL
;
287 NtQueryInformationPort(IN HANDLE PortHandle
,
288 IN PORT_INFORMATION_CLASS PortInformationClass
,
289 OUT PVOID PortInformation
,
290 IN ULONG PortInformationLength
,
291 OUT PULONG ReturnLength
)
294 return STATUS_NOT_IMPLEMENTED
;