[CSRSRV] Only when CSRSRV is compiled in debugging mode, should we display debugging...
[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
852 CsrDereferenceThread(CsrThread);
853 }
854 else if (ReplyCode == CsrReplyPending)
855 {
856 ReplyMsg = NULL;
857 ReplyPort = CsrApiPort;
858 }
859 else
860 {
861 if (ReceiveMsg.CsrCaptureData)
862 {
863 CsrReleaseCapturedArguments(&ReceiveMsg);
864 }
865 CsrDereferenceThread(CsrThread);
866 }
867 }
868 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
869 {
870 ReplyMsg = NULL;
871 ReplyPort = CsrApiPort;
872 }
873 _SEH2_END;
874 }
875
876 /* We're out of the loop for some reason, terminate! */
877 NtTerminateThread(NtCurrentThread(), Status);
878 return Status;
879 }
880
881 /*++
882 * @name CsrApiPortInitialize
883 *
884 * The CsrApiPortInitialize routine initializes the LPC Port used for
885 * communications with the Client/Server Runtime (CSR) and initializes the
886 * static thread that will handle connection requests and APIs.
887 *
888 * @param None
889 *
890 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
891 *
892 * @remarks None.
893 *
894 *--*/
895 NTSTATUS
896 NTAPI
897 CsrApiPortInitialize(VOID)
898 {
899 ULONG Size;
900 OBJECT_ATTRIBUTES ObjectAttributes;
901 NTSTATUS Status;
902 HANDLE hRequestEvent, hThread;
903 CLIENT_ID ClientId;
904 PLIST_ENTRY ListHead, NextEntry;
905 PCSR_THREAD ServerThread;
906
907 /* Calculate how much space we'll need for the Port Name */
908 Size = CsrDirectoryName.Length + sizeof(CSR_PORT_NAME) + sizeof(WCHAR);
909
910 /* Create the buffer for it */
911 CsrApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
912 if (!CsrApiPortName.Buffer) return STATUS_NO_MEMORY;
913
914 /* Setup the rest of the empty string */
915 CsrApiPortName.Length = 0;
916 CsrApiPortName.MaximumLength = (USHORT)Size;
917 RtlAppendUnicodeStringToString(&CsrApiPortName, &CsrDirectoryName);
918 RtlAppendUnicodeToString(&CsrApiPortName, UNICODE_PATH_SEP);
919 RtlAppendUnicodeToString(&CsrApiPortName, CSR_PORT_NAME);
920 if (CsrDebug & 1)
921 {
922 DPRINT1("CSRSS: Creating %wZ port and associated threads\n", &CsrApiPortName);
923 DPRINT1("CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n",
924 sizeof(CSR_API_CONNECTINFO), sizeof(CSR_API_MESSAGE));
925 }
926
927 /* FIXME: Create a Security Descriptor */
928
929 /* Initialize the Attributes */
930 InitializeObjectAttributes(&ObjectAttributes,
931 &CsrApiPortName,
932 0,
933 NULL,
934 NULL /* FIXME: Use the Security Descriptor */);
935
936 /* Create the Port Object */
937 Status = NtCreatePort(&CsrApiPort,
938 &ObjectAttributes,
939 sizeof(CSR_API_CONNECTINFO),
940 sizeof(CSR_API_MESSAGE),
941 16 * PAGE_SIZE);
942 if (NT_SUCCESS(Status))
943 {
944 /* Create the event the Port Thread will use */
945 Status = NtCreateEvent(&hRequestEvent,
946 EVENT_ALL_ACCESS,
947 NULL,
948 SynchronizationEvent,
949 FALSE);
950 if (NT_SUCCESS(Status))
951 {
952 /* Create the Request Thread */
953 Status = RtlCreateUserThread(NtCurrentProcess(),
954 NULL,
955 TRUE,
956 0,
957 0,
958 0,
959 (PVOID)CsrApiRequestThread,
960 (PVOID)hRequestEvent,
961 &hThread,
962 &ClientId);
963 if (NT_SUCCESS(Status))
964 {
965 /* Add this as a static thread to CSRSRV */
966 CsrAddStaticServerThread(hThread, &ClientId, CsrThreadIsServerThread);
967
968 /* Get the Thread List Pointers */
969 ListHead = &CsrRootProcess->ThreadList;
970 NextEntry = ListHead->Flink;
971
972 /* Start looping the list */
973 while (NextEntry != ListHead)
974 {
975 /* Get the Thread */
976 ServerThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
977
978 /* Start it up */
979 Status = NtResumeThread(ServerThread->ThreadHandle, NULL);
980
981 /* Is this a Server Thread? */
982 if (ServerThread->Flags & CsrThreadIsServerThread)
983 {
984 /* If so, then wait for it to initialize */
985 Status = NtWaitForSingleObject(hRequestEvent, FALSE, NULL);
986 ASSERT(NT_SUCCESS(Status));
987 }
988
989 /* Next thread */
990 NextEntry = NextEntry->Flink;
991 }
992
993 /* We don't need this anymore */
994 NtClose(hRequestEvent);
995 }
996 }
997 }
998
999 /* Return */
1000 return Status;
1001 }
1002
1003 /*++
1004 * @name CsrConnectToUser
1005 * @implemented NT4
1006 *
1007 * The CsrConnectToUser connects to the User subsystem.
1008 *
1009 * @param None
1010 *
1011 * @return A pointer to the CSR Thread
1012 *
1013 * @remarks None.
1014 *
1015 *--*/
1016 PCSR_THREAD
1017 NTAPI
1018 CsrConnectToUser(VOID)
1019 {
1020 NTSTATUS Status;
1021 ANSI_STRING DllName;
1022 UNICODE_STRING TempName;
1023 HANDLE hUser32;
1024 STRING StartupName;
1025 PTEB Teb = NtCurrentTeb();
1026 PCSR_THREAD CsrThread;
1027 BOOLEAN Connected;
1028
1029 /* Check if we didn't already find it */
1030 if (!CsrClientThreadSetup)
1031 {
1032 /* Get the DLL Handle for user32.dll */
1033 RtlInitAnsiString(&DllName, "user32");
1034 RtlAnsiStringToUnicodeString(&TempName, &DllName, TRUE);
1035 Status = LdrGetDllHandle(NULL,
1036 NULL,
1037 &TempName,
1038 &hUser32);
1039 RtlFreeUnicodeString(&TempName);
1040
1041 /* If we got the handle, get the Client Thread Startup Entrypoint */
1042 if (NT_SUCCESS(Status))
1043 {
1044 RtlInitAnsiString(&StartupName,"ClientThreadSetup");
1045 Status = LdrGetProcedureAddress(hUser32,
1046 &StartupName,
1047 0,
1048 (PVOID)&CsrClientThreadSetup);
1049 }
1050 }
1051
1052 /* Connect to user32 */
1053 _SEH2_TRY
1054 {
1055 Connected = CsrClientThreadSetup();
1056 }
1057 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1058 {
1059 Connected = FALSE;
1060 }
1061 _SEH2_END;
1062
1063 if (!Connected)
1064 {
1065 DPRINT1("CSRSS: CsrConnectToUser failed\n");
1066 return NULL;
1067 }
1068
1069 /* Save pointer to this thread in TEB */
1070 CsrAcquireProcessLock();
1071 CsrThread = CsrLocateThreadInProcess(NULL, &Teb->ClientId);
1072 CsrReleaseProcessLock();
1073 if (CsrThread) Teb->CsrClientThread = CsrThread;
1074
1075 /* Return it */
1076 return CsrThread;
1077 }
1078
1079 /*++
1080 * @name CsrQueryApiPort
1081 * @implemented NT4
1082 *
1083 * The CsrQueryApiPort routine returns a handle to the CSR API LPC port.
1084 *
1085 * @param None.
1086 *
1087 * @return A handle to the port.
1088 *
1089 * @remarks None.
1090 *
1091 *--*/
1092 HANDLE
1093 NTAPI
1094 CsrQueryApiPort(VOID)
1095 {
1096 return CsrApiPort;
1097 }
1098
1099 /*++
1100 * @name CsrCaptureArguments
1101 * @implemented NT5.1
1102 *
1103 * The CsrCaptureArguments routine validates a CSR Capture Buffer and
1104 * re-captures it into a server CSR Capture Buffer.
1105 *
1106 * @param CsrThread
1107 * Pointer to the CSR Thread performing the validation.
1108 *
1109 * @param ApiMessage
1110 * Pointer to the CSR API Message containing the Capture Buffer
1111 * that needs to be validated.
1112 *
1113 * @return TRUE if validation succeeded, FALSE otherwise.
1114 *
1115 * @remarks None.
1116 *
1117 *--*/
1118 BOOLEAN
1119 NTAPI
1120 CsrCaptureArguments(IN PCSR_THREAD CsrThread,
1121 IN PCSR_API_MESSAGE ApiMessage)
1122 {
1123 PCSR_CAPTURE_BUFFER LocalCaptureBuffer = NULL, RemoteCaptureBuffer = NULL;
1124 SIZE_T BufferDistance;
1125 ULONG Length = 0;
1126 ULONG PointerCount;
1127 PULONG_PTR OffsetPointer;
1128 ULONG_PTR CurrentOffset;
1129
1130 /* Use SEH to make sure this is valid */
1131 _SEH2_TRY
1132 {
1133 /* Get the buffer we got from whoever called NTDLL */
1134 LocalCaptureBuffer = ApiMessage->CsrCaptureData;
1135 Length = LocalCaptureBuffer->Size;
1136
1137 /* Now check if the buffer is inside our mapped section */
1138 if (((ULONG_PTR)LocalCaptureBuffer < CsrThread->Process->ClientViewBase) ||
1139 (((ULONG_PTR)LocalCaptureBuffer + Length) >= CsrThread->Process->ClientViewBounds))
1140 {
1141 /* Return failure */
1142 DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView\n");
1143 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1144 _SEH2_YIELD(return FALSE);
1145 }
1146
1147 /* Check if the Length is valid */
1148 if ((FIELD_OFFSET(CSR_CAPTURE_BUFFER, PointerOffsetsArray) +
1149 (LocalCaptureBuffer->PointerCount * sizeof(PVOID)) > Length) ||
1150 (LocalCaptureBuffer->PointerCount > MAXUSHORT))
1151 {
1152 #ifdef CSR_DBG
1153 DPRINT1("*** CSRSS: CaptureBuffer %p has bad length\n", LocalCaptureBuffer);
1154 if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
1155 #endif
1156 /* Return failure */
1157 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1158 _SEH2_YIELD(return FALSE);
1159 }
1160 }
1161 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1162 {
1163 /* Return failure */
1164 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1165 _SEH2_YIELD(return FALSE);
1166 } _SEH2_END;
1167
1168 /* We validated the incoming buffer, now allocate the remote one */
1169 RemoteCaptureBuffer = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, Length);
1170 if (!RemoteCaptureBuffer)
1171 {
1172 /* We're out of memory */
1173 ApiMessage->Status = STATUS_NO_MEMORY;
1174 return FALSE;
1175 }
1176
1177 /* Copy the client's buffer */
1178 RtlMoveMemory(RemoteCaptureBuffer, LocalCaptureBuffer, Length);
1179
1180 /* Calculate the difference between our buffer and the client's */
1181 BufferDistance = (ULONG_PTR)RemoteCaptureBuffer - (ULONG_PTR)LocalCaptureBuffer;
1182
1183 /*
1184 * All the pointer offsets correspond to pointers which point
1185 * to the remote data buffer instead of the local one.
1186 */
1187 PointerCount = RemoteCaptureBuffer->PointerCount;
1188 OffsetPointer = RemoteCaptureBuffer->PointerOffsetsArray;
1189 while (PointerCount--)
1190 {
1191 CurrentOffset = *OffsetPointer;
1192
1193 if (CurrentOffset != 0)
1194 {
1195 /* Get the pointer corresponding to the offset */
1196 CurrentOffset += (ULONG_PTR)ApiMessage;
1197
1198 /* Validate the bounds of the current pointed pointer */
1199 if ((*(PULONG_PTR)CurrentOffset >= CsrThread->Process->ClientViewBase) &&
1200 (*(PULONG_PTR)CurrentOffset < CsrThread->Process->ClientViewBounds))
1201 {
1202 /* Modify the pointed pointer to take into account its new position */
1203 *(PULONG_PTR)CurrentOffset += BufferDistance;
1204 }
1205 else
1206 {
1207 #ifdef CSR_DBG
1208 DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of ClientView\n");
1209 if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
1210 #endif
1211 /* Invalid pointer, fail */
1212 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1213 }
1214 }
1215
1216 ++OffsetPointer;
1217 }
1218
1219 /* Check if we got success */
1220 if (ApiMessage->Status != STATUS_SUCCESS)
1221 {
1222 /* Failure. Free the buffer and return */
1223 RtlFreeHeap(CsrHeap, 0, RemoteCaptureBuffer);
1224 return FALSE;
1225 }
1226 else
1227 {
1228 /* Success, save the previous buffer and use the remote capture buffer */
1229 RemoteCaptureBuffer->PreviousCaptureBuffer = LocalCaptureBuffer;
1230 ApiMessage->CsrCaptureData = RemoteCaptureBuffer;
1231 }
1232
1233 /* Success */
1234 return TRUE;
1235 }
1236
1237 /*++
1238 * @name CsrReleaseCapturedArguments
1239 * @implemented NT5.1
1240 *
1241 * The CsrReleaseCapturedArguments routine releases a Capture Buffer
1242 * that was previously captured with CsrCaptureArguments.
1243 *
1244 * @param ApiMessage
1245 * Pointer to the CSR API Message containing the Capture Buffer
1246 * that needs to be released.
1247 *
1248 * @return None.
1249 *
1250 * @remarks None.
1251 *
1252 *--*/
1253 VOID
1254 NTAPI
1255 CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage)
1256 {
1257 PCSR_CAPTURE_BUFFER RemoteCaptureBuffer, LocalCaptureBuffer;
1258 SIZE_T BufferDistance;
1259 ULONG PointerCount;
1260 PULONG_PTR OffsetPointer;
1261 ULONG_PTR CurrentOffset;
1262
1263 /* Get the remote capture buffer */
1264 RemoteCaptureBuffer = ApiMessage->CsrCaptureData;
1265
1266 /* Do not continue if there is no captured buffer */
1267 if (!RemoteCaptureBuffer) return;
1268
1269 /* If there is one, get the corresponding local capture buffer */
1270 LocalCaptureBuffer = RemoteCaptureBuffer->PreviousCaptureBuffer;
1271
1272 /* Free the previous one and use again the local capture buffer */
1273 RemoteCaptureBuffer->PreviousCaptureBuffer = NULL;
1274 ApiMessage->CsrCaptureData = LocalCaptureBuffer;
1275
1276 /* Calculate the difference between our buffer and the client's */
1277 BufferDistance = (ULONG_PTR)RemoteCaptureBuffer - (ULONG_PTR)LocalCaptureBuffer;
1278
1279 /*
1280 * All the pointer offsets correspond to pointers which point
1281 * to the local data buffer instead of the remote one (revert
1282 * the logic of CsrCaptureArguments).
1283 */
1284 PointerCount = RemoteCaptureBuffer->PointerCount;
1285 OffsetPointer = RemoteCaptureBuffer->PointerOffsetsArray;
1286 while (PointerCount--)
1287 {
1288 CurrentOffset = *OffsetPointer;
1289
1290 if (CurrentOffset != 0)
1291 {
1292 /* Get the pointer corresponding to the offset */
1293 CurrentOffset += (ULONG_PTR)ApiMessage;
1294
1295 /* Modify the pointed pointer to take into account its new position */
1296 *(PULONG_PTR)CurrentOffset -= BufferDistance;
1297 }
1298
1299 ++OffsetPointer;
1300 }
1301
1302 /* Copy the data back */
1303 RtlMoveMemory(LocalCaptureBuffer, RemoteCaptureBuffer, RemoteCaptureBuffer->Size);
1304
1305 /* Free our allocated buffer */
1306 RtlFreeHeap(CsrHeap, 0, RemoteCaptureBuffer);
1307 }
1308
1309 /*++
1310 * @name CsrValidateMessageBuffer
1311 * @implemented NT5.1
1312 *
1313 * The CsrValidateMessageBuffer routine validates a captured message buffer
1314 * present in the CSR Api Message
1315 *
1316 * @param ApiMessage
1317 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1318 *
1319 * @param Buffer
1320 * Pointer to the message buffer to validate.
1321 *
1322 * @param ElementCount
1323 * Number of elements contained in the message buffer.
1324 *
1325 * @param ElementSize
1326 * Size of each element.
1327 *
1328 * @return TRUE if validation succeeded, FALSE otherwise.
1329 *
1330 * @remarks None.
1331 *
1332 *--*/
1333 BOOLEAN
1334 NTAPI
1335 CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage,
1336 IN PVOID *Buffer,
1337 IN ULONG ElementCount,
1338 IN ULONG ElementSize)
1339 {
1340 PCSR_CAPTURE_BUFFER CaptureBuffer = ApiMessage->CsrCaptureData;
1341 SIZE_T BufferDistance = (ULONG_PTR)Buffer - (ULONG_PTR)ApiMessage;
1342 ULONG PointerCount;
1343 PULONG_PTR OffsetPointer;
1344
1345 /*
1346 * Check whether we have a valid buffer pointer, elements
1347 * of non-trivial size and that we don't overflow.
1348 */
1349 if (!Buffer || ElementSize == 0 ||
1350 (ULONGLONG)ElementCount * ElementSize > (ULONGLONG)0xFFFFFFFF)
1351 {
1352 return FALSE;
1353 }
1354
1355 /* Check if didn't get a buffer and there aren't any arguments to check */
1356 // if (!*Buffer && (ElementCount * ElementSize == 0))
1357 if (!*Buffer && ElementCount == 0) // Here ElementSize != 0 therefore only ElementCount can be == 0
1358 return TRUE;
1359
1360 /* Check if we have no capture buffer */
1361 if (!CaptureBuffer)
1362 {
1363 /*
1364 * In this case, check only the Process ID
1365 * and if there is a match, we succeed.
1366 */
1367 if (NtCurrentTeb()->ClientId.UniqueProcess ==
1368 ApiMessage->Header.ClientId.UniqueProcess)
1369 {
1370 return TRUE;
1371 }
1372 }
1373 else
1374 {
1375 /* Make sure that there is still space left in the buffer */
1376 if ((CaptureBuffer->Size - (ULONG_PTR)*Buffer + (ULONG_PTR)CaptureBuffer) >=
1377 (ElementCount * ElementSize))
1378 {
1379 /* Perform the validation test */
1380 PointerCount = CaptureBuffer->PointerCount;
1381 OffsetPointer = CaptureBuffer->PointerOffsetsArray;
1382 while (PointerCount--)
1383 {
1384 /*
1385 * The pointer offset must be equal to the delta between
1386 * the addresses of the buffer and of the API message.
1387 */
1388 if (*OffsetPointer == BufferDistance)
1389 {
1390 return TRUE;
1391 }
1392 ++OffsetPointer;
1393 }
1394 }
1395 }
1396
1397 /* Failure */
1398 #ifdef CSR_DBG
1399 DPRINT1("CSRSRV: Bad message buffer %p\n", ApiMessage);
1400 if (NtCurrentPeb()->BeingDebugged) DbgBreakPoint();
1401 #endif
1402 return FALSE;
1403 }
1404
1405 /*++
1406 * @name CsrValidateMessageString
1407 * @implemented NT5.1
1408 *
1409 * The CsrValidateMessageString validates a captured Wide-Character String
1410 * present in a CSR API Message.
1411 *
1412 * @param ApiMessage
1413 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1414 *
1415 * @param MessageString
1416 * Pointer to the buffer containing the string to validate.
1417 *
1418 * @return TRUE if validation succeeded, FALSE otherwise.
1419 *
1420 * @remarks None.
1421 *
1422 *--*/
1423 BOOLEAN
1424 NTAPI
1425 CsrValidateMessageString(IN PCSR_API_MESSAGE ApiMessage,
1426 IN PWSTR *MessageString)
1427 {
1428 if (MessageString)
1429 {
1430 return CsrValidateMessageBuffer(ApiMessage,
1431 (PVOID*)MessageString,
1432 wcslen(*MessageString) + 1,
1433 sizeof(WCHAR));
1434 }
1435 else
1436 {
1437 return FALSE;
1438 }
1439 }
1440
1441 /* EOF */