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