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