a0b3de17c550e09686997449e32f8ce49c58ac6e
[reactos.git] / subsystems / win32 / csrsrv / api.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Client/Server Runtime SubSystem
4 * FILE: subsystems/win32/csrsrv/api.c
5 * PURPOSE: CSR Server DLL API LPC Implementation
6 * "\Windows\ApiPort" port process management functions
7 * PROGRAMMERS: Alex Ionescu (alex@relsoft.net)
8 */
9
10 /* INCLUDES *******************************************************************/
11
12 #include "srv.h"
13
14 #include <ndk/kefuncs.h>
15
16 #define NDEBUG
17 #include <debug.h>
18
19 /* GLOBALS ********************************************************************/
20
21 BOOLEAN (*CsrClientThreadSetup)(VOID) = NULL;
22 UNICODE_STRING CsrApiPortName;
23 volatile ULONG CsrpStaticThreadCount;
24 volatile ULONG CsrpDynamicThreadTotal;
25 extern ULONG CsrMaxApiRequestThreads;
26
27 /* FUNCTIONS ******************************************************************/
28
29 /*++
30 * @name CsrCallServerFromServer
31 * @implemented NT4
32 *
33 * The CsrCallServerFromServer routine calls a CSR API from within a server.
34 * It avoids using LPC messages since the request isn't coming from a client.
35 *
36 * @param ReceiveMsg
37 * Pointer to the CSR API Message to send to the server.
38 *
39 * @param ReplyMsg
40 * Pointer to the CSR API Message to receive from the server.
41 *
42 * @return STATUS_SUCCESS in case of success, STATUS_ILLEGAL_FUNCTION
43 * if the ApiNumber is invalid, or STATUS_ACCESS_VIOLATION if there
44 * was a problem executing the API.
45 *
46 * @remarks None.
47 *
48 *--*/
49 NTSTATUS
50 NTAPI
51 CsrCallServerFromServer(IN PCSR_API_MESSAGE ReceiveMsg,
52 IN OUT PCSR_API_MESSAGE ReplyMsg)
53 {
54 ULONG ServerId;
55 PCSR_SERVER_DLL ServerDll;
56 ULONG ApiId;
57 CSR_REPLY_CODE ReplyCode = CsrReplyImmediately;
58
59 /* Get the Server ID */
60 ServerId = CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg->ApiNumber);
61
62 /* Make sure that the ID is within limits, and the Server DLL loaded */
63 if ((ServerId >= CSR_SERVER_DLL_MAX) ||
64 (!(ServerDll = CsrLoadedServerDll[ServerId])))
65 {
66 /* We are beyond the Maximum Server ID */
67 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n", ServerId, ServerDll);
68 ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
69 return STATUS_ILLEGAL_FUNCTION;
70 }
71 else
72 {
73 /* Get the API ID, normalized with our Base ID */
74 ApiId = CSR_API_NUMBER_TO_API_ID(ReceiveMsg->ApiNumber) - ServerDll->ApiBase;
75
76 /* Make sure that the ID is within limits, and the entry exists */
77 if ((ApiId >= ServerDll->HighestApiSupported) ||
78 ((ServerDll->ValidTable) && !(ServerDll->ValidTable[ApiId])))
79 {
80 /* We are beyond the Maximum API ID, or it doesn't exist */
81 #ifdef CSR_DBG
82 DPRINT1("API: %d\n", ApiId);
83 DPRINT1("CSRSS: %lx (%s) is invalid ApiTableIndex for %Z or is an "
84 "invalid API to call from the server.\n",
85 ApiId,
86 ((ServerDll->NameTable) && (ServerDll->NameTable[ApiId])) ?
87 ServerDll->NameTable[ApiId] : "*** UNKNOWN ***",
88 &ServerDll->Name);
89 if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
90 #endif
91 ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
92 return STATUS_ILLEGAL_FUNCTION;
93 }
94 }
95
96 #ifdef CSR_DBG
97 if (CsrDebug & 2)
98 {
99 DPRINT1("CSRSS: %s Api Request received from server process\n",
100 ServerDll->NameTable[ApiId]);
101 }
102 #endif
103
104 /* Validation complete, start SEH */
105 _SEH2_TRY
106 {
107 /* Call the API, get the reply code and return the result */
108 ReplyMsg->Status = ServerDll->DispatchTable[ApiId](ReceiveMsg, &ReplyCode);
109 }
110 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
111 {
112 /* If we got an exception, return access violation */
113 ReplyMsg->Status = STATUS_ACCESS_VIOLATION;
114 }
115 _SEH2_END;
116
117 /* Return success */
118 return STATUS_SUCCESS;
119 }
120
121 /*++
122 * @name CsrApiHandleConnectionRequest
123 *
124 * The CsrApiHandleConnectionRequest routine handles and accepts a new
125 * connection request to the CSR API LPC Port.
126 *
127 * @param ApiMessage
128 * Pointer to the incoming CSR API Message which contains the
129 * connection request.
130 *
131 * @return STATUS_SUCCESS in case of success, or status code which caused
132 * the routine to error.
133 *
134 * @remarks This routine is responsible for attaching the Shared Section to
135 * new clients connecting to CSR.
136 *
137 *--*/
138 NTSTATUS
139 NTAPI
140 CsrApiHandleConnectionRequest(IN PCSR_API_MESSAGE ApiMessage)
141 {
142 PCSR_THREAD CsrThread = NULL;
143 PCSR_PROCESS CsrProcess = NULL;
144 NTSTATUS Status = STATUS_SUCCESS;
145 PCSR_API_CONNECTINFO ConnectInfo = &ApiMessage->ConnectionInfo;
146 BOOLEAN AllowConnection = FALSE;
147 REMOTE_PORT_VIEW RemotePortView;
148 HANDLE ServerPort;
149
150 /* Acquire the Process Lock */
151 CsrAcquireProcessLock();
152
153 /* Lookup the CSR Thread */
154 CsrThread = CsrLocateThreadByClientId(NULL, &ApiMessage->Header.ClientId);
155
156 /* Check if we have a thread */
157 if (CsrThread)
158 {
159 /* Get the Process and make sure we have it as well */
160 CsrProcess = CsrThread->Process;
161 if (CsrProcess)
162 {
163 /* Reference the Process */
164 CsrLockedReferenceProcess(CsrProcess);
165
166 /* Attach the Shared Section */
167 Status = CsrSrvAttachSharedSection(CsrProcess, ConnectInfo);
168 if (NT_SUCCESS(Status))
169 {
170 /* Allow the connection and return debugging flag */
171 ConnectInfo->DebugFlags = CsrDebug;
172 AllowConnection = TRUE;
173 }
174
175 /* Dereference the Process */
176 CsrLockedDereferenceProcess(CsrProcess);
177 }
178 }
179
180 /* Release the Process Lock */
181 CsrReleaseProcessLock();
182
183 /* Setup the Port View Structure */
184 RemotePortView.Length = sizeof(REMOTE_PORT_VIEW);
185 RemotePortView.ViewSize = 0;
186 RemotePortView.ViewBase = NULL;
187
188 /* Save the Process ID */
189 ConnectInfo->ServerProcessId = NtCurrentTeb()->ClientId.UniqueProcess;
190
191 /* Accept the Connection */
192 ASSERT(!AllowConnection || (AllowConnection && CsrProcess));
193 Status = NtAcceptConnectPort(&ServerPort,
194 AllowConnection ? UlongToPtr(CsrProcess->SequenceNumber) : 0,
195 &ApiMessage->Header,
196 AllowConnection,
197 NULL,
198 &RemotePortView);
199 if (!NT_SUCCESS(Status))
200 {
201 DPRINT1("CSRSS: NtAcceptConnectPort - failed. Status == %X\n", Status);
202 }
203 else if (AllowConnection)
204 {
205 if (CsrDebug & 2)
206 {
207 DPRINT1("CSRSS: ClientId: %lx.%lx has ClientView: Base=%p, Size=%lx\n",
208 ApiMessage->Header.ClientId.UniqueProcess,
209 ApiMessage->Header.ClientId.UniqueThread,
210 RemotePortView.ViewBase,
211 RemotePortView.ViewSize);
212 }
213
214 /* Set some Port Data in the Process */
215 CsrProcess->ClientPort = ServerPort;
216 CsrProcess->ClientViewBase = (ULONG_PTR)RemotePortView.ViewBase;
217 CsrProcess->ClientViewBounds = (ULONG_PTR)((ULONG_PTR)RemotePortView.ViewBase +
218 (ULONG_PTR)RemotePortView.ViewSize);
219
220 /* Complete the connection */
221 Status = NtCompleteConnectPort(ServerPort);
222 if (!NT_SUCCESS(Status))
223 {
224 DPRINT1("CSRSS: NtCompleteConnectPort - failed. Status == %X\n", Status);
225 }
226 }
227 else
228 {
229 DPRINT1("CSRSS: Rejecting Connection Request from ClientId: %lx.%lx\n",
230 ApiMessage->Header.ClientId.UniqueProcess,
231 ApiMessage->Header.ClientId.UniqueThread);
232 }
233
234 /* Return status to caller */
235 return Status;
236 }
237
238 /*++
239 * @name CsrpCheckRequestThreads
240 *
241 * The CsrpCheckRequestThreads routine checks if there are no more threads
242 * to handle CSR API Requests, and creates a new thread if possible, to
243 * avoid starvation.
244 *
245 * @param None.
246 *
247 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
248 * if a new thread couldn't be created.
249 *
250 * @remarks None.
251 *
252 *--*/
253 NTSTATUS
254 NTAPI
255 CsrpCheckRequestThreads(VOID)
256 {
257 HANDLE hThread;
258 CLIENT_ID ClientId;
259 NTSTATUS Status;
260
261 /* Decrease the count, and see if we're out */
262 if (InterlockedDecrementUL(&CsrpStaticThreadCount) == 0)
263 {
264 /* Check if we've still got space for a Dynamic Thread */
265 if (CsrpDynamicThreadTotal < CsrMaxApiRequestThreads)
266 {
267 /* Create a new dynamic thread */
268 Status = RtlCreateUserThread(NtCurrentProcess(),
269 NULL,
270 TRUE,
271 0,
272 0,
273 0,
274 (PVOID)CsrApiRequestThread,
275 NULL,
276 &hThread,
277 &ClientId);
278 /* Check success */
279 if (NT_SUCCESS(Status))
280 {
281 /* Increase the thread counts */
282 InterlockedIncrementUL(&CsrpStaticThreadCount);
283 InterlockedIncrementUL(&CsrpDynamicThreadTotal);
284
285 /* Add a new server thread */
286 if (CsrAddStaticServerThread(hThread,
287 &ClientId,
288 CsrThreadIsServerThread))
289 {
290 /* Activate it */
291 NtResumeThread(hThread, NULL);
292 }
293 else
294 {
295 /* Failed to create a new static thread */
296 InterlockedDecrementUL(&CsrpStaticThreadCount);
297 InterlockedDecrementUL(&CsrpDynamicThreadTotal);
298
299 /* Terminate it */
300 DPRINT1("Failing\n");
301 NtTerminateThread(hThread, 0);
302 NtClose(hThread);
303
304 /* Return */
305 return STATUS_UNSUCCESSFUL;
306 }
307 }
308 }
309 }
310
311 /* Success */
312 return STATUS_SUCCESS;
313 }
314
315 /*++
316 * @name CsrApiRequestThread
317 *
318 * The CsrApiRequestThread routine handles incoming messages or connection
319 * requests on the CSR API LPC Port.
320 *
321 * @param Parameter
322 * System-default user-defined parameter. Unused.
323 *
324 * @return The thread exit code, if the thread is terminated.
325 *
326 * @remarks Before listening on the port, the routine will first attempt
327 * to connect to the user subsystem.
328 *
329 *--*/
330 NTSTATUS
331 NTAPI
332 CsrApiRequestThread(IN PVOID Parameter)
333 {
334 PTEB Teb = NtCurrentTeb();
335 LARGE_INTEGER TimeOut;
336 PCSR_THREAD CurrentThread, CsrThread;
337 NTSTATUS Status;
338 CSR_REPLY_CODE ReplyCode;
339 PCSR_API_MESSAGE ReplyMsg;
340 CSR_API_MESSAGE ReceiveMsg;
341 PCSR_PROCESS CsrProcess;
342 PHARDERROR_MSG HardErrorMsg;
343 PVOID PortContext;
344 PCSR_SERVER_DLL ServerDll;
345 PCLIENT_DIED_MSG ClientDiedMsg;
346 PDBGKM_MSG DebugMessage;
347 ULONG ServerId, ApiId, MessageType, i;
348 HANDLE ReplyPort;
349
350 /* Setup LPC loop port and message */
351 ReplyMsg = NULL;
352 ReplyPort = CsrApiPort;
353
354 /* Connect to user32 */
355 while (!CsrConnectToUser())
356 {
357 /* Set up the timeout for the connect (30 seconds) */
358 TimeOut.QuadPart = -30 * 1000 * 1000 * 10;
359
360 /* Keep trying until we get a response */
361 Teb->Win32ClientInfo[0] = 0;
362 NtDelayExecution(FALSE, &TimeOut);
363 }
364
365 /* Get our thread */
366 CurrentThread = Teb->CsrClientThread;
367
368 /* If we got an event... */
369 if (Parameter)
370 {
371 /* Set it, to let stuff waiting on us load */
372 Status = NtSetEvent((HANDLE)Parameter, NULL);
373 ASSERT(NT_SUCCESS(Status));
374
375 /* Increase the Thread Counts */
376 InterlockedIncrementUL(&CsrpStaticThreadCount);
377 InterlockedIncrementUL(&CsrpDynamicThreadTotal);
378 }
379
380 /* Now start the loop */
381 while (TRUE)
382 {
383 /* Make sure the real CID is set */
384 Teb->RealClientId = Teb->ClientId;
385
386 #ifdef CSR_DBG
387 /* Debug check */
388 if (Teb->CountOfOwnedCriticalSections)
389 {
390 DPRINT1("CSRSRV: FATAL ERROR. CsrThread is Idle while holding %lu critical sections\n",
391 Teb->CountOfOwnedCriticalSections);
392 DPRINT1("CSRSRV: Last Receive Message %lx ReplyMessage %lx\n",
393 &ReceiveMsg, ReplyMsg);
394 DbgBreakPoint();
395 }
396 #endif
397
398 /* Wait for a message to come through */
399 Status = NtReplyWaitReceivePort(ReplyPort,
400 &PortContext,
401 &ReplyMsg->Header,
402 &ReceiveMsg.Header);
403
404 /* Check if we didn't get success */
405 if (Status != STATUS_SUCCESS)
406 {
407 /* Was it a failure or another success code? */
408 if (!NT_SUCCESS(Status))
409 {
410 #ifdef CSR_DBG
411 /* Check for specific status cases */
412 if ((Status != STATUS_INVALID_CID) &&
413 (Status != STATUS_UNSUCCESSFUL) &&
414 ((Status != STATUS_INVALID_HANDLE) || (ReplyPort == CsrApiPort)))
415 {
416 /* Notify the debugger */
417 DPRINT1("CSRSS: ReceivePort failed - Status == %X\n", Status);
418 DPRINT1("CSRSS: ReplyPortHandle %lx CsrApiPort %lx\n", ReplyPort, CsrApiPort);
419 }
420 #endif
421
422 /* We failed big time, so start out fresh */
423 ReplyMsg = NULL;
424 ReplyPort = CsrApiPort;
425 continue;
426 }
427 else
428 {
429 /* A strange "success" code, just try again */
430 DPRINT1("NtReplyWaitReceivePort returned \"success\" status 0x%x\n", Status);
431 continue;
432 }
433 }
434
435 // ASSERT(ReceiveMsg.Header.u1.s1.TotalLength >= sizeof(PORT_MESSAGE));
436 // ASSERT(ReceiveMsg.Header.u1.s1.TotalLength < sizeof(ReceiveMsg));
437
438 /* Use whatever Client ID we got */
439 Teb->RealClientId = ReceiveMsg.Header.ClientId;
440
441 /* Get the Message Type */
442 MessageType = ReceiveMsg.Header.u2.s2.Type;
443
444 /* Handle connection requests */
445 if (MessageType == LPC_CONNECTION_REQUEST)
446 {
447 /* Handle the Connection Request */
448 CsrApiHandleConnectionRequest(&ReceiveMsg);
449
450 ReplyMsg = NULL;
451 ReplyPort = CsrApiPort;
452 continue;
453 }
454
455 /* It's some other kind of request. Get the lock for the lookup */
456 CsrAcquireProcessLock();
457
458 /* Now do the lookup to get the CSR_THREAD */
459 CsrThread = CsrLocateThreadByClientId(&CsrProcess,
460 &ReceiveMsg.Header.ClientId);
461
462 /* Did we find a thread? */
463 if (!CsrThread)
464 {
465 /* This wasn't a CSR Thread, release lock */
466 CsrReleaseProcessLock();
467
468 /* If this was an exception, handle it */
469 if (MessageType == LPC_EXCEPTION)
470 {
471 ReplyMsg = &ReceiveMsg;
472 ReplyPort = CsrApiPort;
473 ReplyMsg->Status = DBG_CONTINUE;
474 }
475 else if (MessageType == LPC_PORT_CLOSED ||
476 MessageType == LPC_CLIENT_DIED)
477 {
478 /* The Client or Port are gone, loop again */
479 ReplyMsg = NULL;
480 ReplyPort = CsrApiPort;
481 }
482 else if (MessageType == LPC_ERROR_EVENT)
483 {
484 /* If it's a hard error, handle this too */
485 HardErrorMsg = (PHARDERROR_MSG)&ReceiveMsg;
486
487 /* Default it to unhandled */
488 HardErrorMsg->Response = ResponseNotHandled;
489
490 /* Check if there are free api threads */
491 CsrpCheckRequestThreads();
492 if (CsrpStaticThreadCount)
493 {
494 /* Loop every Server DLL */
495 for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
496 {
497 /* Get the Server DLL */
498 ServerDll = CsrLoadedServerDll[i];
499
500 /* Check if it's valid and if it has a Hard Error Callback */
501 if ((ServerDll) && (ServerDll->HardErrorCallback))
502 {
503 /* Call it */
504 ServerDll->HardErrorCallback(NULL /* == CsrThread */, HardErrorMsg);
505
506 /* If it's handled, get out of here */
507 if (HardErrorMsg->Response != ResponseNotHandled) break;
508 }
509 }
510 }
511
512 /* Increase the thread count */
513 InterlockedIncrementUL(&CsrpStaticThreadCount);
514
515 /* If the response was 0xFFFFFFFF, we'll ignore it */
516 if (HardErrorMsg->Response == 0xFFFFFFFF)
517 {
518 ReplyMsg = NULL;
519 ReplyPort = CsrApiPort;
520 }
521 else
522 {
523 ReplyMsg = &ReceiveMsg;
524 ReplyPort = CsrApiPort;
525 }
526 }
527 else if (MessageType == LPC_REQUEST)
528 {
529 /* This is an API Message coming from a non-CSR Thread */
530 ReplyMsg = &ReceiveMsg;
531 ReplyPort = CsrApiPort;
532 ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
533 }
534 else if (MessageType == LPC_DATAGRAM)
535 {
536 /* This is an API call, get the Server ID */
537 ServerId = CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg.ApiNumber);
538
539 /* Make sure that the ID is within limits, and the Server DLL loaded */
540 ServerDll = NULL;
541 if ((ServerId >= CSR_SERVER_DLL_MAX) ||
542 (!(ServerDll = CsrLoadedServerDll[ServerId])))
543 {
544 /* We are beyond the Maximum Server ID */
545 #ifdef CSR_DBG
546 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
547 ServerId, ServerDll);
548 if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
549 #endif
550
551 ReplyMsg = NULL;
552 ReplyPort = CsrApiPort;
553 continue;
554 }
555
556 /* Get the API ID, normalized with our Base ID */
557 ApiId = CSR_API_NUMBER_TO_API_ID(ReceiveMsg.ApiNumber) - ServerDll->ApiBase;
558
559 /* Make sure that the ID is within limits, and the entry exists */
560 if (ApiId >= ServerDll->HighestApiSupported)
561 {
562 /* We are beyond the Maximum API ID, or it doesn't exist */
563 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
564 CSR_API_NUMBER_TO_API_ID(ReceiveMsg.ApiNumber),
565 &ServerDll->Name);
566
567 ReplyPort = CsrApiPort;
568 ReplyMsg = NULL;
569 continue;
570 }
571
572 #ifdef CSR_DBG
573 if (CsrDebug & 2)
574 {
575 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
576 Teb->ClientId.UniqueThread,
577 ReceiveMsg.Header.ClientId.UniqueProcess,
578 ReceiveMsg.Header.ClientId.UniqueThread,
579 ServerDll->NameTable[ApiId],
580 NULL);
581 }
582 #endif
583
584 /* Assume success */
585 ReceiveMsg.Status = STATUS_SUCCESS;
586
587 /* Validation complete, start SEH */
588 _SEH2_TRY
589 {
590 /* Make sure we have enough threads */
591 CsrpCheckRequestThreads();
592
593 /* Call the API and get the reply code */
594 ReplyMsg = NULL;
595 ReplyPort = CsrApiPort;
596 ServerDll->DispatchTable[ApiId](&ReceiveMsg, &ReplyCode);
597
598 /* Increase the static thread count */
599 InterlockedIncrementUL(&CsrpStaticThreadCount);
600 }
601 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
602 {
603 ReplyMsg = NULL;
604 ReplyPort = CsrApiPort;
605 }
606 _SEH2_END;
607 }
608 else
609 {
610 /* Some other ignored message type */
611 ReplyMsg = NULL;
612 ReplyPort = CsrApiPort;
613 }
614
615 /* Keep going */
616 continue;
617 }
618
619 /* We have a valid thread, was this an LPC Request? */
620 if (MessageType != LPC_REQUEST)
621 {
622 /* It's not an API, check if the client died */
623 if (MessageType == LPC_CLIENT_DIED)
624 {
625 /* Get the information and check if it matches our thread */
626 ClientDiedMsg = (PCLIENT_DIED_MSG)&ReceiveMsg;
627 if (ClientDiedMsg->CreateTime.QuadPart == CsrThread->CreateTime.QuadPart)
628 {
629 /* Now we reply to the dying client */
630 ReplyPort = CsrThread->Process->ClientPort;
631
632 /* Reference the thread */
633 CsrLockedReferenceThread(CsrThread);
634
635 /* Destroy the thread in the API Message */
636 CsrDestroyThread(&ReceiveMsg.Header.ClientId);
637
638 /* Check if the thread was actually ourselves */
639 if (CsrProcess->ThreadCount == 1)
640 {
641 /* Kill the process manually here */
642 CsrDestroyProcess(&CsrThread->ClientId, 0);
643 }
644
645 /* Remove our extra reference */
646 CsrLockedDereferenceThread(CsrThread);
647 }
648
649 /* Release the lock and keep looping */
650 CsrReleaseProcessLock();
651
652 ReplyMsg = NULL;
653 ReplyPort = CsrApiPort;
654 continue;
655 }
656
657 /* Reference the thread and release the lock */
658 CsrLockedReferenceThread(CsrThread);
659 CsrReleaseProcessLock();
660
661 /* Check if this was an exception */
662 if (MessageType == LPC_EXCEPTION)
663 {
664 /* Kill the process */
665 NtTerminateProcess(CsrProcess->ProcessHandle, STATUS_ABANDONED);
666
667 /* Destroy it from CSR */
668 CsrDestroyProcess(&ReceiveMsg.Header.ClientId, STATUS_ABANDONED);
669
670 /* Return a Debug Message */
671 DebugMessage = (PDBGKM_MSG)&ReceiveMsg;
672 DebugMessage->ReturnedStatus = DBG_CONTINUE;
673 ReplyMsg = &ReceiveMsg;
674 ReplyPort = CsrApiPort;
675
676 /* Remove our extra reference */
677 CsrDereferenceThread(CsrThread);
678 }
679 else if (MessageType == LPC_ERROR_EVENT)
680 {
681 /* If it's a hard error, handle this too */
682 HardErrorMsg = (PHARDERROR_MSG)&ReceiveMsg;
683
684 /* Default it to unhandled */
685 HardErrorMsg->Response = ResponseNotHandled;
686
687 /* Check if there are free api threads */
688 CsrpCheckRequestThreads();
689 if (CsrpStaticThreadCount)
690 {
691 /* Loop every Server DLL */
692 for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
693 {
694 /* Get the Server DLL */
695 ServerDll = CsrLoadedServerDll[i];
696
697 /* Check if it's valid and if it has a Hard Error Callback */
698 if ((ServerDll) && (ServerDll->HardErrorCallback))
699 {
700 /* Call it */
701 ServerDll->HardErrorCallback(CsrThread, HardErrorMsg);
702
703 /* If it's handled, get out of here */
704 if (HardErrorMsg->Response != ResponseNotHandled) break;
705 }
706 }
707 }
708
709 /* Increase the thread count */
710 InterlockedIncrementUL(&CsrpStaticThreadCount);
711
712 /* If the response was 0xFFFFFFFF, we'll ignore it */
713 if (HardErrorMsg->Response == 0xFFFFFFFF)
714 {
715 ReplyMsg = NULL;
716 ReplyPort = CsrApiPort;
717 }
718 else
719 {
720 CsrDereferenceThread(CsrThread);
721 ReplyMsg = &ReceiveMsg;
722 ReplyPort = CsrApiPort;
723 }
724 }
725 else
726 {
727 /* Something else */
728 CsrDereferenceThread(CsrThread);
729 ReplyMsg = NULL;
730 }
731
732 /* Keep looping */
733 continue;
734 }
735
736 /* We got an API Request */
737 CsrLockedReferenceThread(CsrThread);
738 CsrReleaseProcessLock();
739
740 /* This is an API call, get the Server ID */
741 ServerId = CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg.ApiNumber);
742
743 /* Make sure that the ID is within limits, and the Server DLL loaded */
744 ServerDll = NULL;
745 if ((ServerId >= CSR_SERVER_DLL_MAX) ||
746 (!(ServerDll = CsrLoadedServerDll[ServerId])))
747 {
748 /* We are beyond the Maximum Server ID */
749 #ifdef CSR_DBG
750 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
751 ServerId, ServerDll);
752 if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
753 #endif
754
755 ReplyPort = CsrApiPort;
756 ReplyMsg = &ReceiveMsg;
757 ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
758 CsrDereferenceThread(CsrThread);
759 continue;
760 }
761
762 /* Get the API ID, normalized with our Base ID */
763 ApiId = CSR_API_NUMBER_TO_API_ID(ReceiveMsg.ApiNumber) - ServerDll->ApiBase;
764
765 /* Make sure that the ID is within limits, and the entry exists */
766 if (ApiId >= ServerDll->HighestApiSupported)
767 {
768 /* We are beyond the Maximum API ID, or it doesn't exist */
769 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
770 CSR_API_NUMBER_TO_API_ID(ReceiveMsg.ApiNumber),
771 &ServerDll->Name);
772
773 ReplyPort = CsrApiPort;
774 ReplyMsg = &ReceiveMsg;
775 ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
776 CsrDereferenceThread(CsrThread);
777 continue;
778 }
779
780 #ifdef CSR_DBG
781 if (CsrDebug & 2)
782 {
783 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x, Process %08x - %08x\n",
784 Teb->ClientId.UniqueThread,
785 ReceiveMsg.Header.ClientId.UniqueProcess,
786 ReceiveMsg.Header.ClientId.UniqueThread,
787 ServerDll->NameTable[ApiId],
788 CsrThread,
789 CsrThread->Process,
790 CsrProcess);
791 }
792 #endif
793
794 /* Assume success */
795 ReplyMsg = &ReceiveMsg;
796 ReceiveMsg.Status = STATUS_SUCCESS;
797
798 /* Now we reply to a particular client */
799 ReplyPort = CsrThread->Process->ClientPort;
800
801 /* Check if there's a capture buffer */
802 if (ReceiveMsg.CsrCaptureData)
803 {
804 /* Capture the arguments */
805 if (!CsrCaptureArguments(CsrThread, &ReceiveMsg))
806 {
807 /* Ignore this message if we failed to get the arguments */
808 CsrDereferenceThread(CsrThread);
809 continue;
810 }
811 }
812
813 /* Validation complete, start SEH */
814 _SEH2_TRY
815 {
816 /* Make sure we have enough threads */
817 CsrpCheckRequestThreads();
818
819 Teb->CsrClientThread = CsrThread;
820
821 /* Call the API, get the reply code and return the result */
822 ReplyCode = CsrReplyImmediately;
823 ReplyMsg->Status = ServerDll->DispatchTable[ApiId](&ReceiveMsg, &ReplyCode);
824
825 /* Increase the static thread count */
826 InterlockedIncrementUL(&CsrpStaticThreadCount);
827
828 Teb->CsrClientThread = CurrentThread;
829
830 if (ReplyCode == CsrReplyAlreadySent)
831 {
832 if (ReceiveMsg.CsrCaptureData)
833 {
834 CsrReleaseCapturedArguments(&ReceiveMsg);
835 }
836 ReplyMsg = NULL;
837 ReplyPort = CsrApiPort;
838 CsrDereferenceThread(CsrThread);
839 }
840 else if (ReplyCode == CsrReplyDeadClient)
841 {
842 /* Reply to the death message */
843 NTSTATUS Status2;
844 Status2 = NtReplyPort(ReplyPort, &ReplyMsg->Header);
845 if (!NT_SUCCESS(Status2))
846 DPRINT1("CSRSS: Error while replying to the death message, Status 0x%lx\n", Status2);
847
848 /* Reply back to the API port now */
849 ReplyMsg = NULL;
850 ReplyPort = CsrApiPort;
851 CsrDereferenceThread(CsrThread);
852 }
853 else if (ReplyCode == CsrReplyPending)
854 {
855 ReplyMsg = NULL;
856 ReplyPort = CsrApiPort;
857 }
858 else
859 {
860 if (ReceiveMsg.CsrCaptureData)
861 {
862 CsrReleaseCapturedArguments(&ReceiveMsg);
863 }
864 CsrDereferenceThread(CsrThread);
865 }
866 }
867 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
868 {
869 ReplyMsg = NULL;
870 ReplyPort = CsrApiPort;
871 }
872 _SEH2_END;
873 }
874
875 /* We're out of the loop for some reason, terminate! */
876 NtTerminateThread(NtCurrentThread(), Status);
877 return Status;
878 }
879
880 /*++
881 * @name CsrApiPortInitialize
882 *
883 * The CsrApiPortInitialize routine initializes the LPC Port used for
884 * communications with the Client/Server Runtime (CSR) and initializes the
885 * static thread that will handle connection requests and APIs.
886 *
887 * @param None
888 *
889 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
890 *
891 * @remarks None.
892 *
893 *--*/
894 NTSTATUS
895 NTAPI
896 CsrApiPortInitialize(VOID)
897 {
898 ULONG Size;
899 OBJECT_ATTRIBUTES ObjectAttributes;
900 NTSTATUS Status;
901 HANDLE hRequestEvent, hThread;
902 CLIENT_ID ClientId;
903 PLIST_ENTRY ListHead, NextEntry;
904 PCSR_THREAD ServerThread;
905
906 /* Calculate how much space we'll need for the Port Name */
907 Size = CsrDirectoryName.Length + sizeof(CSR_PORT_NAME) + sizeof(WCHAR);
908
909 /* Create the buffer for it */
910 CsrApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
911 if (!CsrApiPortName.Buffer) return STATUS_NO_MEMORY;
912
913 /* Setup the rest of the empty string */
914 CsrApiPortName.Length = 0;
915 CsrApiPortName.MaximumLength = (USHORT)Size;
916 RtlAppendUnicodeStringToString(&CsrApiPortName, &CsrDirectoryName);
917 RtlAppendUnicodeToString(&CsrApiPortName, UNICODE_PATH_SEP);
918 RtlAppendUnicodeToString(&CsrApiPortName, CSR_PORT_NAME);
919 if (CsrDebug & 1)
920 {
921 DPRINT1("CSRSS: Creating %wZ port and associated threads\n", &CsrApiPortName);
922 DPRINT1("CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n",
923 sizeof(CSR_API_CONNECTINFO), sizeof(CSR_API_MESSAGE));
924 }
925
926 /* FIXME: Create a Security Descriptor */
927
928 /* Initialize the Attributes */
929 InitializeObjectAttributes(&ObjectAttributes,
930 &CsrApiPortName,
931 0,
932 NULL,
933 NULL /* FIXME: Use the Security Descriptor */);
934
935 /* Create the Port Object */
936 Status = NtCreatePort(&CsrApiPort,
937 &ObjectAttributes,
938 sizeof(CSR_API_CONNECTINFO),
939 sizeof(CSR_API_MESSAGE),
940 16 * PAGE_SIZE);
941 if (NT_SUCCESS(Status))
942 {
943 /* Create the event the Port Thread will use */
944 Status = NtCreateEvent(&hRequestEvent,
945 EVENT_ALL_ACCESS,
946 NULL,
947 SynchronizationEvent,
948 FALSE);
949 if (NT_SUCCESS(Status))
950 {
951 /* Create the Request Thread */
952 Status = RtlCreateUserThread(NtCurrentProcess(),
953 NULL,
954 TRUE,
955 0,
956 0,
957 0,
958 (PVOID)CsrApiRequestThread,
959 (PVOID)hRequestEvent,
960 &hThread,
961 &ClientId);
962 if (NT_SUCCESS(Status))
963 {
964 /* Add this as a static thread to CSRSRV */
965 CsrAddStaticServerThread(hThread, &ClientId, CsrThreadIsServerThread);
966
967 /* Get the Thread List Pointers */
968 ListHead = &CsrRootProcess->ThreadList;
969 NextEntry = ListHead->Flink;
970
971 /* Start looping the list */
972 while (NextEntry != ListHead)
973 {
974 /* Get the Thread */
975 ServerThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
976
977 /* Start it up */
978 Status = NtResumeThread(ServerThread->ThreadHandle, NULL);
979
980 /* Is this a Server Thread? */
981 if (ServerThread->Flags & CsrThreadIsServerThread)
982 {
983 /* If so, then wait for it to initialize */
984 Status = NtWaitForSingleObject(hRequestEvent, FALSE, NULL);
985 ASSERT(NT_SUCCESS(Status));
986 }
987
988 /* Next thread */
989 NextEntry = NextEntry->Flink;
990 }
991
992 /* We don't need this anymore */
993 NtClose(hRequestEvent);
994 }
995 }
996 }
997
998 /* Return */
999 return Status;
1000 }
1001
1002 /*++
1003 * @name CsrConnectToUser
1004 * @implemented NT4
1005 *
1006 * The CsrConnectToUser connects to the User subsystem.
1007 *
1008 * @param None
1009 *
1010 * @return A pointer to the CSR Thread
1011 *
1012 * @remarks None.
1013 *
1014 *--*/
1015 PCSR_THREAD
1016 NTAPI
1017 CsrConnectToUser(VOID)
1018 {
1019 NTSTATUS Status;
1020 ANSI_STRING DllName;
1021 UNICODE_STRING TempName;
1022 HANDLE hUser32;
1023 STRING StartupName;
1024 PTEB Teb = NtCurrentTeb();
1025 PCSR_THREAD CsrThread;
1026 BOOLEAN Connected;
1027
1028 /* Check if we didn't already find it */
1029 if (!CsrClientThreadSetup)
1030 {
1031 /* Get the DLL Handle for user32.dll */
1032 RtlInitAnsiString(&DllName, "user32");
1033 RtlAnsiStringToUnicodeString(&TempName, &DllName, TRUE);
1034 Status = LdrGetDllHandle(NULL,
1035 NULL,
1036 &TempName,
1037 &hUser32);
1038 RtlFreeUnicodeString(&TempName);
1039
1040 /* If we got the handle, get the Client Thread Startup Entrypoint */
1041 if (NT_SUCCESS(Status))
1042 {
1043 RtlInitAnsiString(&StartupName,"ClientThreadSetup");
1044 Status = LdrGetProcedureAddress(hUser32,
1045 &StartupName,
1046 0,
1047 (PVOID)&CsrClientThreadSetup);
1048 }
1049 }
1050
1051 /* Connect to user32 */
1052 _SEH2_TRY
1053 {
1054 Connected = CsrClientThreadSetup();
1055 }
1056 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1057 {
1058 Connected = FALSE;
1059 }
1060 _SEH2_END;
1061
1062 if (!Connected)
1063 {
1064 DPRINT1("CSRSS: CsrConnectToUser failed\n");
1065 return NULL;
1066 }
1067
1068 /* Save pointer to this thread in TEB */
1069 CsrAcquireProcessLock();
1070 CsrThread = CsrLocateThreadInProcess(NULL, &Teb->ClientId);
1071 CsrReleaseProcessLock();
1072 if (CsrThread) Teb->CsrClientThread = CsrThread;
1073
1074 /* Return it */
1075 return CsrThread;
1076 }
1077
1078 /*++
1079 * @name CsrQueryApiPort
1080 * @implemented NT4
1081 *
1082 * The CsrQueryApiPort routine returns a handle to the CSR API LPC port.
1083 *
1084 * @param None.
1085 *
1086 * @return A handle to the port.
1087 *
1088 * @remarks None.
1089 *
1090 *--*/
1091 HANDLE
1092 NTAPI
1093 CsrQueryApiPort(VOID)
1094 {
1095 return CsrApiPort;
1096 }
1097
1098 /*++
1099 * @name CsrCaptureArguments
1100 * @implemented NT5.1
1101 *
1102 * The CsrCaptureArguments routine validates a CSR Capture Buffer and
1103 * re-captures it into a server CSR Capture Buffer.
1104 *
1105 * @param CsrThread
1106 * Pointer to the CSR Thread performing the validation.
1107 *
1108 * @param ApiMessage
1109 * Pointer to the CSR API Message containing the Capture Buffer
1110 * that needs to be validated.
1111 *
1112 * @return TRUE if validation succeeded, FALSE otherwise.
1113 *
1114 * @remarks None.
1115 *
1116 *--*/
1117 BOOLEAN
1118 NTAPI
1119 CsrCaptureArguments(IN PCSR_THREAD CsrThread,
1120 IN PCSR_API_MESSAGE ApiMessage)
1121 {
1122 PCSR_PROCESS CsrProcess = CsrThread->Process;
1123 PCSR_CAPTURE_BUFFER ClientCaptureBuffer, ServerCaptureBuffer = NULL;
1124 ULONG_PTR EndOfClientBuffer;
1125 SIZE_T SizeOfBufferThroughOffsetsArray;
1126 SIZE_T BufferDistance;
1127 ULONG Length;
1128 ULONG PointerCount;
1129 PULONG_PTR OffsetPointer;
1130 ULONG_PTR CurrentOffset;
1131
1132 /* Get the buffer we got from whoever called NTDLL */
1133 ClientCaptureBuffer = ApiMessage->CsrCaptureData;
1134
1135 /* Use SEH to validate and capture the client buffer */
1136 _SEH2_TRY
1137 {
1138 /* Check whether at least the buffer's header is inside our mapped section */
1139 if ( ((ULONG_PTR)ClientCaptureBuffer < CsrProcess->ClientViewBase) ||
1140 (((ULONG_PTR)ClientCaptureBuffer + FIELD_OFFSET(CSR_CAPTURE_BUFFER, PointerOffsetsArray))
1141 >= CsrProcess->ClientViewBounds) )
1142 {
1143 #ifdef CSR_DBG
1144 DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView 1\n");
1145 if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
1146 #endif
1147 /* Return failure */
1148 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1149 _SEH2_YIELD(return FALSE);
1150 }
1151
1152 /* Capture the buffer length */
1153 Length = ((volatile CSR_CAPTURE_BUFFER*)ClientCaptureBuffer)->Size;
1154
1155 /*
1156 * Now check if the remaining of the buffer is inside our mapped section.
1157 * Take also care for any possible wrap-around of the buffer end-address.
1158 */
1159 EndOfClientBuffer = (ULONG_PTR)ClientCaptureBuffer + Length;
1160 if ( (EndOfClientBuffer < (ULONG_PTR)ClientCaptureBuffer) ||
1161 (EndOfClientBuffer >= CsrProcess->ClientViewBounds) )
1162 {
1163 #ifdef CSR_DBG
1164 DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView 2\n");
1165 if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
1166 #endif
1167 /* Return failure */
1168 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1169 _SEH2_YIELD(return FALSE);
1170 }
1171
1172 /* Capture the pointer count */
1173 PointerCount = ((volatile CSR_CAPTURE_BUFFER*)ClientCaptureBuffer)->PointerCount;
1174
1175 /*
1176 * Check whether the total buffer size and the pointer count are consistent
1177 * -- the array of offsets must be contained inside the buffer.
1178 */
1179 SizeOfBufferThroughOffsetsArray =
1180 FIELD_OFFSET(CSR_CAPTURE_BUFFER, PointerOffsetsArray) +
1181 (PointerCount * sizeof(PVOID));
1182 if ( (PointerCount > MAXUSHORT) ||
1183 (SizeOfBufferThroughOffsetsArray > Length) )
1184 {
1185 #ifdef CSR_DBG
1186 DPRINT1("*** CSRSS: CaptureBuffer %p has bad length\n", ClientCaptureBuffer);
1187 if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
1188 #endif
1189 /* Return failure */
1190 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1191 _SEH2_YIELD(return FALSE);
1192 }
1193 }
1194 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1195 {
1196 #ifdef CSR_DBG
1197 DPRINT1("*** CSRSS: Took exception during capture %x\n", _SEH2_GetExceptionCode());
1198 if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
1199 #endif
1200 /* Return failure */
1201 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1202 _SEH2_YIELD(return FALSE);
1203 }
1204 _SEH2_END;
1205
1206 /* We validated the client buffer, now allocate the server buffer */
1207 ServerCaptureBuffer = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, Length);
1208 if (!ServerCaptureBuffer)
1209 {
1210 /* We're out of memory */
1211 ApiMessage->Status = STATUS_NO_MEMORY;
1212 return FALSE;
1213 }
1214
1215 /*
1216 * Copy the client's buffer and ensure we use the correct buffer length
1217 * and pointer count we captured and used for validation earlier on.
1218 */
1219 _SEH2_TRY
1220 {
1221 RtlMoveMemory(ServerCaptureBuffer, ClientCaptureBuffer, Length);
1222 }
1223 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1224 {
1225 #ifdef CSR_DBG
1226 DPRINT1("*** CSRSS: Took exception during capture %x\n", _SEH2_GetExceptionCode());
1227 if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
1228 #endif
1229 /* Failure, free the buffer and return */
1230 RtlFreeHeap(CsrHeap, 0, ServerCaptureBuffer);
1231 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1232 _SEH2_YIELD(return FALSE);
1233 }
1234 _SEH2_END;
1235
1236 ServerCaptureBuffer->Size = Length;
1237 ServerCaptureBuffer->PointerCount = PointerCount;
1238
1239 /* Calculate the difference between our buffer and the client's */
1240 BufferDistance = (ULONG_PTR)ServerCaptureBuffer - (ULONG_PTR)ClientCaptureBuffer;
1241
1242 /*
1243 * All the pointer offsets correspond to pointers that point
1244 * to the server data buffer instead of the client one.
1245 */
1246 // PointerCount = ServerCaptureBuffer->PointerCount;
1247 OffsetPointer = ServerCaptureBuffer->PointerOffsetsArray;
1248 while (PointerCount--)
1249 {
1250 CurrentOffset = *OffsetPointer;
1251
1252 if (CurrentOffset != 0)
1253 {
1254 /*
1255 * Check whether the offset is pointer-aligned and whether
1256 * it points inside CSR_API_MESSAGE::Data.ApiMessageData.
1257 */
1258 if ( ((CurrentOffset & (sizeof(PVOID)-1)) != 0) ||
1259 (CurrentOffset < FIELD_OFFSET(CSR_API_MESSAGE, Data.ApiMessageData)) ||
1260 (CurrentOffset >= sizeof(CSR_API_MESSAGE)) )
1261 {
1262 #ifdef CSR_DBG
1263 DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of message\n");
1264 if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
1265 #endif
1266 /* Invalid pointer, fail */
1267 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1268 break;
1269 }
1270
1271 /* Get the pointer corresponding to the offset */
1272 CurrentOffset += (ULONG_PTR)ApiMessage;
1273
1274 /* Validate the bounds of the current pointed pointer */
1275 if ( (*(PULONG_PTR)CurrentOffset >= ((ULONG_PTR)ClientCaptureBuffer +
1276 SizeOfBufferThroughOffsetsArray)) &&
1277 (*(PULONG_PTR)CurrentOffset <= (EndOfClientBuffer - sizeof(PVOID))) )
1278 {
1279 /* Modify the pointed pointer to take into account its new position */
1280 *(PULONG_PTR)CurrentOffset += BufferDistance;
1281 }
1282 else
1283 {
1284 #ifdef CSR_DBG
1285 DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of ClientView\n");
1286 if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
1287 #endif
1288 /* Invalid pointer, fail */
1289 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1290 break;
1291 }
1292 }
1293
1294 ++OffsetPointer;
1295 }
1296
1297 /* Check if we got success */
1298 if (ApiMessage->Status != STATUS_SUCCESS)
1299 {
1300 /* Failure, free the buffer and return */
1301 RtlFreeHeap(CsrHeap, 0, ServerCaptureBuffer);
1302 return FALSE;
1303 }
1304 else
1305 {
1306 /* Success, save the previous buffer and use the server capture buffer */
1307 ServerCaptureBuffer->PreviousCaptureBuffer = ClientCaptureBuffer;
1308 ApiMessage->CsrCaptureData = ServerCaptureBuffer;
1309 }
1310
1311 /* Success */
1312 return TRUE;
1313 }
1314
1315 /*++
1316 * @name CsrReleaseCapturedArguments
1317 * @implemented NT5.1
1318 *
1319 * The CsrReleaseCapturedArguments routine releases a Capture Buffer
1320 * that was previously captured with CsrCaptureArguments.
1321 *
1322 * @param ApiMessage
1323 * Pointer to the CSR API Message containing the Capture Buffer
1324 * that needs to be released.
1325 *
1326 * @return None.
1327 *
1328 * @remarks None.
1329 *
1330 *--*/
1331 VOID
1332 NTAPI
1333 CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage)
1334 {
1335 PCSR_CAPTURE_BUFFER ServerCaptureBuffer, ClientCaptureBuffer;
1336 SIZE_T BufferDistance;
1337 ULONG PointerCount;
1338 PULONG_PTR OffsetPointer;
1339 ULONG_PTR CurrentOffset;
1340
1341 /* Get the server capture buffer */
1342 ServerCaptureBuffer = ApiMessage->CsrCaptureData;
1343
1344 /* Do not continue if there is no captured buffer */
1345 if (!ServerCaptureBuffer) return;
1346
1347 /* If there is one, get the corresponding client capture buffer */
1348 ClientCaptureBuffer = ServerCaptureBuffer->PreviousCaptureBuffer;
1349
1350 /* Free the previous one and use again the client capture buffer */
1351 ServerCaptureBuffer->PreviousCaptureBuffer = NULL;
1352 ApiMessage->CsrCaptureData = ClientCaptureBuffer;
1353
1354 /* Calculate the difference between our buffer and the client's */
1355 BufferDistance = (ULONG_PTR)ServerCaptureBuffer - (ULONG_PTR)ClientCaptureBuffer;
1356
1357 /*
1358 * All the pointer offsets correspond to pointers that point
1359 * to the client data buffer instead of the server one (reverse
1360 * the logic of CsrCaptureArguments()).
1361 */
1362 PointerCount = ServerCaptureBuffer->PointerCount;
1363 OffsetPointer = ServerCaptureBuffer->PointerOffsetsArray;
1364 while (PointerCount--)
1365 {
1366 CurrentOffset = *OffsetPointer;
1367
1368 if (CurrentOffset != 0)
1369 {
1370 /* Get the pointer corresponding to the offset */
1371 CurrentOffset += (ULONG_PTR)ApiMessage;
1372
1373 /* Modify the pointed pointer to take into account its new position */
1374 *(PULONG_PTR)CurrentOffset -= BufferDistance;
1375 }
1376
1377 ++OffsetPointer;
1378 }
1379
1380 /* Copy the data back into the client buffer */
1381 _SEH2_TRY
1382 {
1383 RtlMoveMemory(ClientCaptureBuffer, ServerCaptureBuffer, ServerCaptureBuffer->Size);
1384 }
1385 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1386 {
1387 #ifdef CSR_DBG
1388 DPRINT1("*** CSRSS: Took exception during release %x\n", _SEH2_GetExceptionCode());
1389 if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
1390 #endif
1391 /* Return failure */
1392 ApiMessage->Status = _SEH2_GetExceptionCode();
1393 }
1394 _SEH2_END;
1395
1396 /* Free our allocated buffer */
1397 RtlFreeHeap(CsrHeap, 0, ServerCaptureBuffer);
1398 }
1399
1400 /*++
1401 * @name CsrValidateMessageBuffer
1402 * @implemented NT5.1
1403 *
1404 * The CsrValidateMessageBuffer routine validates a captured message buffer
1405 * present in the CSR Api Message
1406 *
1407 * @param ApiMessage
1408 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1409 *
1410 * @param Buffer
1411 * Pointer to the message buffer to validate.
1412 *
1413 * @param ElementCount
1414 * Number of elements contained in the message buffer.
1415 *
1416 * @param ElementSize
1417 * Size of each element.
1418 *
1419 * @return TRUE if validation succeeded, FALSE otherwise.
1420 *
1421 * @remarks None.
1422 *
1423 *--*/
1424 BOOLEAN
1425 NTAPI
1426 CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage,
1427 IN PVOID *Buffer,
1428 IN ULONG ElementCount,
1429 IN ULONG ElementSize)
1430 {
1431 PCSR_CAPTURE_BUFFER CaptureBuffer = ApiMessage->CsrCaptureData;
1432 SIZE_T BufferDistance = (ULONG_PTR)Buffer - (ULONG_PTR)ApiMessage;
1433 ULONG PointerCount;
1434 PULONG_PTR OffsetPointer;
1435
1436 /*
1437 * Check whether we have a valid buffer pointer, elements
1438 * of non-trivial size and that we don't overflow.
1439 */
1440 if (!Buffer || ElementSize == 0 ||
1441 (ULONGLONG)ElementCount * ElementSize > (ULONGLONG)MAXULONG)
1442 {
1443 return FALSE;
1444 }
1445
1446 /* Check if didn't get a buffer and there aren't any arguments to check */
1447 // if (!*Buffer && (ElementCount * ElementSize == 0))
1448 if (!*Buffer && ElementCount == 0) // Here ElementSize != 0 therefore only ElementCount can be == 0
1449 return TRUE;
1450
1451 /* Check if we have no capture buffer */
1452 if (!CaptureBuffer)
1453 {
1454 /* In this case, succeed only if the caller is CSRSS */
1455 if (NtCurrentTeb()->ClientId.UniqueProcess ==
1456 ApiMessage->Header.ClientId.UniqueProcess)
1457 {
1458 return TRUE;
1459 }
1460 }
1461 else
1462 {
1463 /* Make sure that there is still space left in the capture buffer */
1464 if ((CaptureBuffer->Size - (ULONG_PTR)*Buffer + (ULONG_PTR)CaptureBuffer) >=
1465 (ElementCount * ElementSize))
1466 {
1467 /* Perform the validation test */
1468 PointerCount = CaptureBuffer->PointerCount;
1469 OffsetPointer = CaptureBuffer->PointerOffsetsArray;
1470 while (PointerCount--)
1471 {
1472 /*
1473 * Find in the array, the pointer offset (from the
1474 * API message) that corresponds to the buffer.
1475 */
1476 if (*OffsetPointer == BufferDistance)
1477 {
1478 return TRUE;
1479 }
1480 ++OffsetPointer;
1481 }
1482 }
1483 }
1484
1485 /* Failure */
1486 #ifdef CSR_DBG
1487 DPRINT1("CSRSRV: Bad message buffer %p\n", ApiMessage);
1488 if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
1489 #endif
1490 return FALSE;
1491 }
1492
1493 /*++
1494 * @name CsrValidateMessageString
1495 * @implemented NT5.1
1496 *
1497 * The CsrValidateMessageString validates a captured Wide-Character String
1498 * present in a CSR API Message.
1499 *
1500 * @param ApiMessage
1501 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1502 *
1503 * @param MessageString
1504 * Pointer to the buffer containing the string to validate.
1505 *
1506 * @return TRUE if validation succeeded, FALSE otherwise.
1507 *
1508 * @remarks None.
1509 *
1510 *--*/
1511 BOOLEAN
1512 NTAPI
1513 CsrValidateMessageString(IN PCSR_API_MESSAGE ApiMessage,
1514 IN PWSTR *MessageString)
1515 {
1516 if (MessageString)
1517 {
1518 return CsrValidateMessageBuffer(ApiMessage,
1519 (PVOID*)MessageString,
1520 wcslen(*MessageString) + 1,
1521 sizeof(WCHAR));
1522 }
1523 else
1524 {
1525 return FALSE;
1526 }
1527 }
1528
1529 /* EOF */