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