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