[NTOS:LPC]: Improve the lisibility of some functions:
[reactos.git] / reactos / ntoskrnl / lpc / port.c
1 /*
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)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #define NDEBUG
13 #include <debug.h>
14
15 /* GLOBALS *******************************************************************/
16
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;
23
24 static GENERIC_MAPPING LpcpPortMapping =
25 {
26 READ_CONTROL | PORT_CONNECT,
27 DELETE | PORT_CONNECT,
28 0,
29 PORT_ALL_ACCESS
30 };
31
32 /* PRIVATE FUNCTIONS *********************************************************/
33
34 BOOLEAN
35 NTAPI
36 INIT_FUNCTION
37 LpcInitSystem(VOID)
38 {
39 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
40 UNICODE_STRING Name;
41
42 /* Setup the LPC Lock */
43 KeInitializeGuardedMutex(&LpcpLock);
44
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,
60 NULL,
61 &LpcPortObjectType);
62
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,
71 NULL,
72 &LpcWaitablePortObjectType);
73
74 /* Allocate the LPC lookaside list */
75 LpcpMaxMessageSize = LPCP_MAX_MESSAGE_SIZE;
76 ExInitializePagedLookasideList(&LpcpMessagesLookaside,
77 NULL,
78 NULL,
79 0,
80 LpcpMaxMessageSize,
81 'McpL',
82 32);
83
84 /* We're done */
85 return TRUE;
86 }
87
88 BOOLEAN
89 NTAPI
90 LpcpValidateClientPort(
91 PETHREAD ClientThread,
92 PLPCP_PORT_OBJECT Port)
93 {
94 PLPCP_PORT_OBJECT ThreadPort;
95
96 /* Get the thread's port */
97 ThreadPort = LpcpGetPortFromThread(ClientThread);
98 if (ThreadPort == NULL)
99 {
100 return FALSE;
101 }
102
103 /* Check if the port matches directly */
104 if ((Port == ThreadPort) ||
105 (Port == ThreadPort->ConnectionPort) ||
106 (Port == ThreadPort->ConnectedPort))
107 {
108 return TRUE;
109 }
110
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))
114 {
115 return TRUE;
116 }
117
118 return FALSE;
119 }
120
121
122 /* PUBLIC FUNCTIONS **********************************************************/
123
124 NTSTATUS
125 NTAPI
126 NtImpersonateClientOfPort(IN HANDLE PortHandle,
127 IN PPORT_MESSAGE ClientMessage)
128 {
129 NTSTATUS Status;
130 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
131 CLIENT_ID ClientId;
132 ULONG MessageId;
133 PLPCP_PORT_OBJECT Port = NULL, ConnectedPort = NULL;
134 PETHREAD ClientThread = NULL;
135 SECURITY_CLIENT_CONTEXT ClientContext;
136
137 PAGED_CODE();
138
139 /* Check the previous mode */
140 PreviousMode = ExGetPreviousMode();
141 if (PreviousMode == KernelMode)
142 {
143 ClientId = ClientMessage->ClientId;
144 MessageId = ClientMessage->MessageId;
145 }
146 else
147 {
148 _SEH2_TRY
149 {
150 ProbeForRead(ClientMessage, sizeof(*ClientMessage), sizeof(PVOID));
151 ClientId = ClientMessage->ClientId;
152 MessageId = ClientMessage->MessageId;
153 }
154 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
155 {
156 DPRINT1("Got exception!\n");
157 _SEH2_YIELD(return _SEH2_GetExceptionCode());
158 }
159 _SEH2_END;
160 }
161
162 /* Reference the port handle */
163 Status = ObReferenceObjectByHandle(PortHandle,
164 PORT_ALL_ACCESS,
165 LpcPortObjectType,
166 PreviousMode,
167 (PVOID*)&Port,
168 NULL);
169 if (!NT_SUCCESS(Status))
170 {
171 DPRINT1("Failed to reference port handle: 0x%ls\n", Status);
172 return Status;
173 }
174
175 /* Make sure this is a connection port */
176 if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_COMMUNICATION_PORT)
177 {
178 /* It isn't, fail */
179 DPRINT1("Port is not a communication port\n");
180 Status = STATUS_INVALID_PORT_HANDLE;
181 goto Cleanup;
182 }
183
184 /* Look up the client thread */
185 Status = PsLookupProcessThreadByCid(&ClientId, NULL, &ClientThread);
186 if (!NT_SUCCESS(Status))
187 {
188 DPRINT1("Failed to lookup client thread: 0x%ls\n", Status);
189 goto Cleanup;
190 }
191
192 /* Acquire the lock */
193 KeAcquireGuardedMutex(&LpcpLock);
194
195 /* Get the connected port and try to reference it */
196 ConnectedPort = Port->ConnectedPort;
197 if ((ConnectedPort == NULL) || !ObReferenceObjectSafe(ConnectedPort))
198 {
199 DPRINT1("Failed to reference the connected port\n");
200 ConnectedPort = NULL;
201 Status = STATUS_PORT_DISCONNECTED;
202 goto CleanupWithLock;
203 }
204
205 /* Check for no-impersonation flag */
206 if ((ULONG_PTR)ClientThread->LpcReplyMessage & LPCP_THREAD_FLAG_NO_IMPERSONATION)
207 {
208 DPRINT1("Reply message has no impersonation flag set\n");
209 Status = STATUS_ACCESS_DENIED;
210 goto CleanupWithLock;
211 }
212
213 /* Check for message id mismatch */
214 if ((ClientThread->LpcReplyMessageId != MessageId) || (MessageId == 0))
215 {
216 DPRINT1("LpcReplyMessageId mismatch: 0x%lx/0x%lx.\n",
217 ClientThread->LpcReplyMessageId, MessageId);
218 Status = STATUS_REPLY_MESSAGE_MISMATCH;
219 goto CleanupWithLock;
220 }
221
222 /* Validate the port */
223 if (!LpcpValidateClientPort(ClientThread, Port))
224 {
225 DPRINT1("LpcpValidateClientPort failed\n");
226 Status = STATUS_REPLY_MESSAGE_MISMATCH;
227 goto CleanupWithLock;
228 }
229
230 /* Release the lock */
231 KeReleaseGuardedMutex(&LpcpLock);
232
233 /* Check if security is static */
234 if (!(ConnectedPort->Flags & LPCP_SECURITY_DYNAMIC))
235 {
236 /* Use the static security for impersonation */
237 Status = SeImpersonateClientEx(&ConnectedPort->StaticSecurity, NULL);
238 goto Cleanup;
239 }
240
241 /* Create new dynamic security */
242 Status = SeCreateClientSecurity(ClientThread,
243 &ConnectedPort->SecurityQos,
244 FALSE,
245 &ClientContext);
246 if (!NT_SUCCESS(Status))
247 {
248 DPRINT1("SeCreateClientSecurity failed\n");
249 goto Cleanup;
250 }
251
252 /* Use dynamic security for impersonation */
253 Status = SeImpersonateClientEx(&ClientContext, NULL);
254
255 /* Get rid of the security context */
256 SeDeleteClientSecurity(&ClientContext);
257
258 Cleanup:
259
260 if (ConnectedPort != NULL)
261 ObDereferenceObject(ConnectedPort);
262
263 if (ClientThread != NULL)
264 ObDereferenceObject(ClientThread);
265
266 ObDereferenceObject(Port);
267
268 return Status;
269
270 CleanupWithLock:
271
272 /* Release the lock */
273 KeReleaseGuardedMutex(&LpcpLock);
274 goto Cleanup;
275 }
276
277 NTSTATUS
278 NTAPI
279 NtQueryPortInformationProcess(VOID)
280 {
281 /* This is all this function does */
282 return STATUS_UNSUCCESSFUL;
283 }
284
285 NTSTATUS
286 NTAPI
287 NtQueryInformationPort(IN HANDLE PortHandle,
288 IN PORT_INFORMATION_CLASS PortInformationClass,
289 OUT PVOID PortInformation,
290 IN ULONG PortInformationLength,
291 OUT PULONG ReturnLength)
292 {
293 UNIMPLEMENTED;
294 return STATUS_NOT_IMPLEMENTED;
295 }
296
297 /* EOF */