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