[CSRSRV]
[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 LONG CsrpStaticThreadCount;
22 volatile LONG 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 = (ULONG)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 = (ULONG)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_CONNECTION_INFO 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(CsrThread->Process);
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 (!(_InterlockedDecrement(&CsrpStaticThreadCount)))
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 _InterlockedIncrement(&CsrpStaticThreadCount);
293 _InterlockedIncrement(&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 _InterlockedDecrement(&CsrpStaticThreadCount);
307 _InterlockedDecrement(&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 _InterlockedIncrement(&CsrpStaticThreadCount);
387 _InterlockedIncrement(&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 bizare "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 == NULL */, 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 _InterlockedIncrement(&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 }
528 }
529 else if (MessageType == LPC_REQUEST)
530 {
531 /* This is an API Message coming from a non-CSR Thread */
532 ReplyMsg = &ReceiveMsg;
533 ReplyPort = CsrApiPort;
534 ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
535 }
536 else if (MessageType == LPC_DATAGRAM)
537 {
538 /* This is an API call, get the Server ID */
539 ServerId = CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg.ApiNumber);
540
541 /* Make sure that the ID is within limits, and the Server DLL loaded */
542 ServerDll = NULL;
543 if ((ServerId >= CSR_SERVER_DLL_MAX) ||
544 (!(ServerDll = CsrLoadedServerDll[ServerId])))
545 {
546 /* We are beyond the Maximum Server ID */
547 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
548 ServerId, ServerDll);
549 DbgBreakPoint();
550
551 ReplyMsg = NULL;
552 ReplyPort = CsrApiPort;
553 continue;
554 }
555
556 /* Get the API ID, normalized with our Base ID */
557 ApiId = CSR_API_NUMBER_TO_API_ID(ReceiveMsg.ApiNumber) - ServerDll->ApiBase;
558
559 /* Make sure that the ID is within limits, and the entry exists */
560 if (ApiId >= ServerDll->HighestApiSupported)
561 {
562 /* We are beyond the Maximum API ID, or it doesn't exist */
563 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
564 CSR_API_NUMBER_TO_API_ID(ReceiveMsg.ApiNumber),
565 &ServerDll->Name);
566
567 ReplyPort = CsrApiPort;
568 ReplyMsg = NULL;
569 continue;
570 }
571
572 if (CsrDebug & 2)
573 {
574 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
575 Teb->ClientId.UniqueThread,
576 ReceiveMsg.Header.ClientId.UniqueProcess,
577 ReceiveMsg.Header.ClientId.UniqueThread,
578 ServerDll->NameTable[ApiId],
579 NULL);
580 }
581
582 /* Assume success */
583 ReceiveMsg.Status = STATUS_SUCCESS;
584
585 /* Validation complete, start SEH */
586 _SEH2_TRY
587 {
588 /* Make sure we have enough threads */
589 CsrpCheckRequestThreads();
590
591 /* Call the API and get the reply code */
592 ReplyMsg = NULL;
593 ReplyPort = CsrApiPort;
594 ServerDll->DispatchTable[ApiId](&ReceiveMsg, &ReplyCode);
595
596 /* Increase the static thread count */
597 _InterlockedIncrement(&CsrpStaticThreadCount);
598 }
599 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
600 {
601 ReplyMsg = NULL;
602 ReplyPort = CsrApiPort;
603 }
604 _SEH2_END;
605 }
606 else
607 {
608 /* Some other ignored message type */
609 ReplyMsg = NULL;
610 ReplyPort = CsrApiPort;
611 }
612
613 /* Keep going */
614 continue;
615 }
616
617 /* We have a valid thread, was this an LPC Request? */
618 if (MessageType != LPC_REQUEST)
619 {
620 /* It's not an API, check if the client died */
621 if (MessageType == LPC_CLIENT_DIED)
622 {
623 /* Get the information and check if it matches our thread */
624 ClientDiedMsg = (PCLIENT_DIED_MSG)&ReceiveMsg;
625 if (ClientDiedMsg->CreateTime.QuadPart == CsrThread->CreateTime.QuadPart)
626 {
627 /* Reference the thread */
628 CsrLockedReferenceThread(CsrThread);
629
630 /* Destroy the thread in the API Message */
631 CsrDestroyThread(&ReceiveMsg.Header.ClientId);
632
633 /* Check if the thread was actually ourselves */
634 if (CsrProcess->ThreadCount == 1)
635 {
636 /* Kill the process manually here */
637 CsrDestroyProcess(&CsrThread->ClientId, 0);
638 }
639
640 /* Remove our extra reference */
641 CsrLockedDereferenceThread(CsrThread);
642 }
643
644 /* Release the lock and keep looping */
645 CsrReleaseProcessLock();
646
647 ReplyMsg = NULL;
648 ReplyPort = CsrApiPort;
649 continue;
650 }
651
652 /* Reference the thread and release the lock */
653 CsrLockedReferenceThread(CsrThread);
654 CsrReleaseProcessLock();
655
656 /* Check if this was an exception */
657 if (MessageType == LPC_EXCEPTION)
658 {
659 /* Kill the process */
660 NtTerminateProcess(CsrProcess->ProcessHandle, STATUS_ABANDONED);
661
662 /* Destroy it from CSR */
663 CsrDestroyProcess(&ReceiveMsg.Header.ClientId, STATUS_ABANDONED);
664
665 /* Return a Debug Message */
666 DebugMessage = (PDBGKM_MSG)&ReceiveMsg;
667 DebugMessage->ReturnedStatus = DBG_CONTINUE;
668 ReplyMsg = &ReceiveMsg;
669 ReplyPort = CsrApiPort;
670
671 /* Remove our extra reference */
672 CsrDereferenceThread(CsrThread);
673 }
674 else if (MessageType == LPC_ERROR_EVENT)
675 {
676 /* If it's a hard error, handle this too */
677 HardErrorMsg = (PHARDERROR_MSG)&ReceiveMsg;
678
679 /* Default it to unhandled */
680 HardErrorMsg->Response = ResponseNotHandled;
681
682 /* Check if there are free api threads */
683 CsrpCheckRequestThreads();
684 if (CsrpStaticThreadCount)
685 {
686 /* Loop every Server DLL */
687 for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
688 {
689 /* Get the Server DLL */
690 ServerDll = CsrLoadedServerDll[i];
691
692 /* Check if it's valid and if it has a Hard Error Callback */
693 if ((ServerDll) && (ServerDll->HardErrorCallback))
694 {
695 /* Call it */
696 ServerDll->HardErrorCallback(CsrThread, HardErrorMsg);
697
698 /* If it's handled, get out of here */
699 if (HardErrorMsg->Response != ResponseNotHandled) break;
700 }
701 }
702 }
703
704 /* Increase the thread count */
705 _InterlockedIncrement(&CsrpStaticThreadCount);
706
707 /* If the response was 0xFFFFFFFF, we'll ignore it */
708 if (HardErrorMsg->Response == 0xFFFFFFFF)
709 {
710 ReplyMsg = NULL;
711 ReplyPort = CsrApiPort;
712 }
713 else
714 {
715 CsrDereferenceThread(CsrThread);
716 ReplyMsg = &ReceiveMsg;
717 ReplyPort = CsrApiPort;
718 }
719 }
720 else
721 {
722 /* Something else */
723 CsrDereferenceThread(CsrThread);
724 ReplyMsg = NULL;
725 }
726
727 /* Keep looping */
728 continue;
729 }
730
731 /* We got an API Request */
732 CsrLockedReferenceThread(CsrThread);
733 CsrReleaseProcessLock();
734
735 /* This is an API call, get the Server ID */
736 ServerId = CSR_API_NUMBER_TO_SERVER_ID(ReceiveMsg.ApiNumber);
737
738 /* Make sure that the ID is within limits, and the Server DLL loaded */
739 ServerDll = NULL;
740 if ((ServerId >= CSR_SERVER_DLL_MAX) ||
741 (!(ServerDll = CsrLoadedServerDll[ServerId])))
742 {
743 /* We are beyond the Maximum Server ID */
744 DPRINT1("CSRSS: %lx is invalid ServerDllIndex (%08x)\n",
745 ServerId, ServerDll);
746 DbgBreakPoint();
747
748 ReplyPort = CsrApiPort;
749 ReplyMsg = &ReceiveMsg;
750 ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
751 CsrDereferenceThread(CsrThread);
752 continue;
753 }
754
755 /* Get the API ID, normalized with our Base ID */
756 ApiId = CSR_API_NUMBER_TO_API_ID(ReceiveMsg.ApiNumber) - ServerDll->ApiBase;
757
758 /* Make sure that the ID is within limits, and the entry exists */
759 if (ApiId >= ServerDll->HighestApiSupported)
760 {
761 /* We are beyond the Maximum API ID, or it doesn't exist */
762 DPRINT1("CSRSS: %lx is invalid ApiTableIndex for %Z\n",
763 CSR_API_NUMBER_TO_API_ID(ReceiveMsg.ApiNumber),
764 &ServerDll->Name);
765
766 ReplyPort = CsrApiPort;
767 ReplyMsg = &ReceiveMsg;
768 ReplyMsg->Status = STATUS_ILLEGAL_FUNCTION;
769 CsrDereferenceThread(CsrThread);
770 continue;
771 }
772
773 if (CsrDebug & 2)
774 {
775 DPRINT1("[%02x] CSRSS: [%02x,%02x] - %s Api called from %08x\n",
776 Teb->ClientId.UniqueThread,
777 ReceiveMsg.Header.ClientId.UniqueProcess,
778 ReceiveMsg.Header.ClientId.UniqueThread,
779 ServerDll->NameTable[ApiId],
780 CsrThread);
781 }
782
783 /* Assume success */
784 ReplyMsg = &ReceiveMsg;
785 ReceiveMsg.Status = STATUS_SUCCESS;
786
787 /* Now we reply to a particular client */
788 ReplyPort = CsrThread->Process->ClientPort;
789
790 /* Check if there's a capture buffer */
791 if (ReceiveMsg.CsrCaptureData)
792 {
793 /* Capture the arguments */
794 if (!CsrCaptureArguments(CsrThread, &ReceiveMsg))
795 {
796 /* Ignore this message if we failed to get the arguments */
797 CsrDereferenceThread(CsrThread);
798 continue;
799 }
800 }
801
802 /* Validation complete, start SEH */
803 _SEH2_TRY
804 {
805 /* Make sure we have enough threads */
806 CsrpCheckRequestThreads();
807
808 Teb->CsrClientThread = CsrThread;
809
810 /* Call the API, get the reply code and return the result */
811 ReplyCode = CsrReplyImmediately;
812 ReplyMsg->Status = ServerDll->DispatchTable[ApiId](&ReceiveMsg, &ReplyCode);
813
814 /* Increase the static thread count */
815 _InterlockedIncrement(&CsrpStaticThreadCount);
816
817 Teb->CsrClientThread = CurrentThread;
818
819 if (ReplyCode == CsrReplyAlreadyDone)
820 {
821 if (ReceiveMsg.CsrCaptureData)
822 {
823 CsrReleaseCapturedArguments(&ReceiveMsg);
824 }
825 ReplyMsg = NULL;
826 ReplyPort = CsrApiPort;
827 CsrDereferenceThread(CsrThread);
828 }
829 else if (ReplyCode == CsrReplyDeadClient)
830 {
831 /* Reply to the death message */
832 NtReplyPort(ReplyPort, &ReplyMsg->Header);
833
834 /* Reply back to the API port now */
835 ReplyMsg = NULL;
836 ReplyPort = CsrApiPort;
837
838 CsrDereferenceThread(CsrThread);
839 }
840 else if (ReplyCode == CsrReplyPending)
841 {
842 ReplyMsg = NULL;
843 ReplyPort = CsrApiPort;
844 }
845 else
846 {
847 if (ReceiveMsg.CsrCaptureData)
848 {
849 CsrReleaseCapturedArguments(&ReceiveMsg);
850 }
851 CsrDereferenceThread(CsrThread);
852 }
853 }
854 _SEH2_EXCEPT(CsrUnhandledExceptionFilter(_SEH2_GetExceptionInformation()))
855 {
856 ReplyMsg = NULL;
857 ReplyPort = CsrApiPort;
858 }
859 _SEH2_END;
860 }
861
862 /* We're out of the loop for some reason, terminate! */
863 NtTerminateThread(NtCurrentThread(), Status);
864 return Status;
865 }
866
867 /*++
868 * @name CsrApiPortInitialize
869 *
870 * The CsrApiPortInitialize routine initializes the LPC Port used for
871 * communications with the Client/Server Runtime (CSR) and initializes the
872 * static thread that will handle connection requests and APIs.
873 *
874 * @param None
875 *
876 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
877 * otherwise.
878 *
879 * @remarks None.
880 *
881 *--*/
882 NTSTATUS
883 NTAPI
884 CsrApiPortInitialize(VOID)
885 {
886 ULONG Size;
887 OBJECT_ATTRIBUTES ObjectAttributes;
888 NTSTATUS Status;
889 HANDLE hRequestEvent, hThread;
890 CLIENT_ID ClientId;
891 PLIST_ENTRY ListHead, NextEntry;
892 PCSR_THREAD ServerThread;
893
894 /* Calculate how much space we'll need for the Port Name */
895 Size = CsrDirectoryName.Length + sizeof(CSR_PORT_NAME) + sizeof(WCHAR);
896
897 /* Create the buffer for it */
898 CsrApiPortName.Buffer = RtlAllocateHeap(CsrHeap, 0, Size);
899 if (!CsrApiPortName.Buffer) return STATUS_NO_MEMORY;
900
901 /* Setup the rest of the empty string */
902 CsrApiPortName.Length = 0;
903 CsrApiPortName.MaximumLength = (USHORT)Size;
904 RtlAppendUnicodeStringToString(&CsrApiPortName, &CsrDirectoryName);
905 RtlAppendUnicodeToString(&CsrApiPortName, UNICODE_PATH_SEP);
906 RtlAppendUnicodeToString(&CsrApiPortName, CSR_PORT_NAME);
907 if (CsrDebug & 1)
908 {
909 DPRINT1("CSRSS: Creating %wZ port and associated threads\n", &CsrApiPortName);
910 DPRINT1("CSRSS: sizeof( CONNECTINFO ) == %ld sizeof( API_MSG ) == %ld\n",
911 sizeof(CSR_CONNECTION_INFO), sizeof(CSR_API_MESSAGE));
912 }
913
914 /* FIXME: Create a Security Descriptor */
915
916 /* Initialize the Attributes */
917 InitializeObjectAttributes(&ObjectAttributes,
918 &CsrApiPortName,
919 0,
920 NULL,
921 NULL /* FIXME*/);
922
923 /* Create the Port Object */
924 Status = NtCreatePort(&CsrApiPort,
925 &ObjectAttributes,
926 LPC_MAX_DATA_LENGTH, // HACK: the real value is: sizeof(CSR_CONNECTION_INFO),
927 LPC_MAX_MESSAGE_LENGTH, // HACK: the real value is: sizeof(CSR_API_MESSAGE),
928 16 * PAGE_SIZE);
929 if (NT_SUCCESS(Status))
930 {
931 /* Create the event the Port Thread will use */
932 Status = NtCreateEvent(&hRequestEvent,
933 EVENT_ALL_ACCESS,
934 NULL,
935 SynchronizationEvent,
936 FALSE);
937 if (NT_SUCCESS(Status))
938 {
939 /* Create the Request Thread */
940 Status = RtlCreateUserThread(NtCurrentProcess(),
941 NULL,
942 TRUE,
943 0,
944 0,
945 0,
946 (PVOID)CsrApiRequestThread,
947 (PVOID)hRequestEvent,
948 &hThread,
949 &ClientId);
950 if (NT_SUCCESS(Status))
951 {
952 /* Add this as a static thread to CSRSRV */
953 CsrAddStaticServerThread(hThread, &ClientId, CsrThreadIsServerThread);
954
955 /* Get the Thread List Pointers */
956 ListHead = &CsrRootProcess->ThreadList;
957 NextEntry = ListHead->Flink;
958
959 /* Start looping the list */
960 while (NextEntry != ListHead)
961 {
962 /* Get the Thread */
963 ServerThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
964
965 /* Start it up */
966 Status = NtResumeThread(ServerThread->ThreadHandle, NULL);
967
968 /* Is this a Server Thread? */
969 if (ServerThread->Flags & CsrThreadIsServerThread)
970 {
971 /* If so, then wait for it to initialize */
972 Status = NtWaitForSingleObject(hRequestEvent, FALSE, NULL);
973 ASSERT(NT_SUCCESS(Status));
974 }
975
976 /* Next thread */
977 NextEntry = NextEntry->Flink;
978 }
979
980 /* We don't need this anymore */
981 NtClose(hRequestEvent);
982 }
983 }
984 }
985
986 /* Return */
987 return Status;
988 }
989
990 /*++
991 * @name CsrConnectToUser
992 * @implemented NT4
993 *
994 * The CsrConnectToUser connects to the User subsystem.
995 *
996 * @param None
997 *
998 * @return A pointer to the CSR Thread
999 *
1000 * @remarks None.
1001 *
1002 *--*/
1003 PCSR_THREAD
1004 NTAPI
1005 CsrConnectToUser(VOID)
1006 {
1007 #if 0 // This code is OK, however it is ClientThreadSetup which sucks.
1008 NTSTATUS Status;
1009 ANSI_STRING DllName;
1010 UNICODE_STRING TempName;
1011 HANDLE hUser32;
1012 STRING StartupName;
1013 PTEB Teb = NtCurrentTeb();
1014 PCSR_THREAD CsrThread;
1015 BOOLEAN Connected;
1016
1017 /* Check if we didn't already find it */
1018 if (!CsrClientThreadSetup)
1019 {
1020 /* Get the DLL Handle for user32.dll */
1021 RtlInitAnsiString(&DllName, "user32");
1022 RtlAnsiStringToUnicodeString(&TempName, &DllName, TRUE);
1023 Status = LdrGetDllHandle(NULL,
1024 NULL,
1025 &TempName,
1026 &hUser32);
1027 RtlFreeUnicodeString(&TempName);
1028
1029 /* If we got the handle, get the Client Thread Startup Entrypoint */
1030 if (NT_SUCCESS(Status))
1031 {
1032 RtlInitAnsiString(&StartupName,"ClientThreadSetup");
1033 Status = LdrGetProcedureAddress(hUser32,
1034 &StartupName,
1035 0,
1036 (PVOID)&CsrClientThreadSetup);
1037 }
1038 }
1039
1040 /* Connect to user32 */
1041 _SEH2_TRY
1042 {
1043 Connected = CsrClientThreadSetup();
1044 }
1045 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1046 {
1047 Connected = FALSE;
1048 } _SEH2_END;
1049
1050 if (!Connected)
1051 {
1052 DPRINT1("CSRSS: CsrConnectToUser failed\n");
1053 return NULL;
1054 }
1055
1056 /* Save pointer to this thread in TEB */
1057 CsrAcquireProcessLock();
1058 CsrThread = CsrLocateThreadInProcess(NULL, &Teb->ClientId);
1059 CsrReleaseProcessLock();
1060 if (CsrThread) Teb->CsrClientThread = CsrThread;
1061
1062 /* Return it */
1063 return CsrThread;
1064
1065 #else
1066
1067 PTEB Teb = NtCurrentTeb();
1068 PCSR_THREAD CsrThread;
1069
1070 /* Save pointer to this thread in TEB */
1071 CsrThread = CsrLocateThreadInProcess(NULL, &Teb->ClientId);
1072 if (CsrThread) Teb->CsrClientThread = CsrThread;
1073
1074 /* Return it */
1075 return CsrThread;
1076 #endif
1077 }
1078
1079 /*++
1080 * @name CsrQueryApiPort
1081 * @implemented NT4
1082 *
1083 * The CsrQueryApiPort routine returns a handle to the CSR API LPC port.
1084 *
1085 * @param None.
1086 *
1087 * @return A handle to the port.
1088 *
1089 * @remarks None.
1090 *
1091 *--*/
1092 HANDLE
1093 NTAPI
1094 CsrQueryApiPort(VOID)
1095 {
1096 DPRINT("CSRSRV: %s called\n", __FUNCTION__);
1097 return CsrApiPort;
1098 }
1099
1100 /*++
1101 * @name CsrCaptureArguments
1102 * @implemented NT5.1
1103 *
1104 * The CsrCaptureArguments routine validates a CSR Capture Buffer and
1105 * re-captures it into a server CSR Capture Buffer.
1106 *
1107 * @param CsrThread
1108 * Pointer to the CSR Thread performing the validation.
1109 *
1110 * @param ApiMessage
1111 * Pointer to the CSR API Message containing the Capture Buffer
1112 * that needs to be validated.
1113 *
1114 * @return TRUE if validation succeeded, FALSE otherwise.
1115 *
1116 * @remarks None.
1117 *
1118 *--*/
1119 BOOLEAN
1120 NTAPI
1121 CsrCaptureArguments(IN PCSR_THREAD CsrThread,
1122 IN PCSR_API_MESSAGE ApiMessage)
1123 {
1124 PCSR_CAPTURE_BUFFER LocalCaptureBuffer = NULL, RemoteCaptureBuffer = NULL;
1125 SIZE_T BufferDistance;
1126 ULONG Length = 0;
1127 ULONG i;
1128
1129 /* Use SEH to make sure this is valid */
1130 _SEH2_TRY
1131 {
1132 /* Get the buffer we got from whoever called NTDLL */
1133 LocalCaptureBuffer = ApiMessage->CsrCaptureData;
1134 Length = LocalCaptureBuffer->Size;
1135
1136 /* Now check if the buffer is inside our mapped section */
1137 if (((ULONG_PTR)LocalCaptureBuffer < CsrThread->Process->ClientViewBase) ||
1138 (((ULONG_PTR)LocalCaptureBuffer + Length) >= CsrThread->Process->ClientViewBounds))
1139 {
1140 /* Return failure */
1141 DPRINT1("*** CSRSS: CaptureBuffer outside of ClientView\n");
1142 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1143 _SEH2_YIELD(return FALSE);
1144 }
1145
1146 /* Check if the Length is valid */
1147 if ((FIELD_OFFSET(CSR_CAPTURE_BUFFER, PointerOffsetsArray) +
1148 (LocalCaptureBuffer->PointerCount * sizeof(PVOID)) > Length) ||
1149 (Length > MAXWORD))
1150 {
1151 /* Return failure */
1152 DPRINT1("*** CSRSS: CaptureBuffer %p has bad length\n", LocalCaptureBuffer);
1153 DbgBreakPoint();
1154 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1155 _SEH2_YIELD(return FALSE);
1156 }
1157 }
1158 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1159 {
1160 /* Return failure */
1161 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1162 _SEH2_YIELD(return FALSE);
1163 } _SEH2_END;
1164
1165 /* We validated the incoming buffer, now allocate the remote one */
1166 RemoteCaptureBuffer = RtlAllocateHeap(CsrHeap, 0, Length);
1167 if (!RemoteCaptureBuffer)
1168 {
1169 /* We're out of memory */
1170 ApiMessage->Status = STATUS_NO_MEMORY;
1171 return FALSE;
1172 }
1173
1174 /* Copy the client's buffer */
1175 RtlMoveMemory(RemoteCaptureBuffer, LocalCaptureBuffer, Length);
1176
1177 /* Calculate the difference between our buffer and the client's */
1178 BufferDistance = (ULONG_PTR)RemoteCaptureBuffer - (ULONG_PTR)LocalCaptureBuffer;
1179
1180 /*
1181 * Convert all the pointer offsets into real pointers, and make
1182 * them point to the remote data buffer instead of the local one.
1183 */
1184 for (i = 0 ; i < RemoteCaptureBuffer->PointerCount ; ++i)
1185 {
1186 if (RemoteCaptureBuffer->PointerOffsetsArray[i] != 0)
1187 {
1188 RemoteCaptureBuffer->PointerOffsetsArray[i] += (ULONG_PTR)ApiMessage;
1189
1190 /* Validate the bounds of the current pointer */
1191 if ((*(PULONG_PTR)RemoteCaptureBuffer->PointerOffsetsArray[i] >= CsrThread->Process->ClientViewBase) &&
1192 (*(PULONG_PTR)RemoteCaptureBuffer->PointerOffsetsArray[i] < CsrThread->Process->ClientViewBounds))
1193 {
1194 /* Modify the pointer to take into account its new position */
1195 *(PULONG_PTR)RemoteCaptureBuffer->PointerOffsetsArray[i] += BufferDistance;
1196 }
1197 else
1198 {
1199 /* Invalid pointer, fail */
1200 DPRINT1("*** CSRSS: CaptureBuffer MessagePointer outside of ClientView\n");
1201 DbgBreakPoint();
1202 ApiMessage->Status = STATUS_INVALID_PARAMETER;
1203 }
1204 }
1205 }
1206
1207 /* Check if we got success */
1208 if (ApiMessage->Status != STATUS_SUCCESS)
1209 {
1210 /* Failure. Free the buffer and return*/
1211 RtlFreeHeap(CsrHeap, 0, RemoteCaptureBuffer);
1212 return FALSE;
1213 }
1214 else
1215 {
1216 /* Success, save the previous buffer */
1217 RemoteCaptureBuffer->PreviousCaptureBuffer = LocalCaptureBuffer;
1218 ApiMessage->CsrCaptureData = RemoteCaptureBuffer;
1219 }
1220
1221 /* Success */
1222 return TRUE;
1223 }
1224
1225 /*++
1226 * @name CsrReleaseCapturedArguments
1227 * @implemented NT5.1
1228 *
1229 * The CsrReleaseCapturedArguments routine releases a Capture Buffer
1230 * that was previously captured with CsrCaptureArguments.
1231 *
1232 * @param ApiMessage
1233 * Pointer to the CSR API Message containing the Capture Buffer
1234 * that needs to be released.
1235 *
1236 * @return None.
1237 *
1238 * @remarks None.
1239 *
1240 *--*/
1241 VOID
1242 NTAPI
1243 CsrReleaseCapturedArguments(IN PCSR_API_MESSAGE ApiMessage)
1244 {
1245 PCSR_CAPTURE_BUFFER RemoteCaptureBuffer, LocalCaptureBuffer;
1246 SIZE_T BufferDistance;
1247 ULONG i;
1248
1249 /* Get the capture buffers */
1250 RemoteCaptureBuffer = ApiMessage->CsrCaptureData;
1251 LocalCaptureBuffer = RemoteCaptureBuffer->PreviousCaptureBuffer;
1252
1253 /* Do not continue if there is no captured buffer */
1254 if (!RemoteCaptureBuffer) return;
1255
1256 /* Free the previous one */
1257 RemoteCaptureBuffer->PreviousCaptureBuffer = NULL;
1258
1259 /* Calculate the difference between our buffer and the client's */
1260 BufferDistance = (ULONG_PTR)RemoteCaptureBuffer - (ULONG_PTR)LocalCaptureBuffer;
1261
1262 /*
1263 * Convert back all the pointers into pointer offsets, and make them
1264 * point to the local data buffer instead of the remote one (revert
1265 * the logic of CsrCaptureArguments).
1266 */
1267 for (i = 0 ; i < RemoteCaptureBuffer->PointerCount ; ++i)
1268 {
1269 if (RemoteCaptureBuffer->PointerOffsetsArray[i] != 0)
1270 {
1271 *(PULONG_PTR)RemoteCaptureBuffer->PointerOffsetsArray[i] -= BufferDistance;
1272 RemoteCaptureBuffer->PointerOffsetsArray[i] -= (ULONG_PTR)ApiMessage;
1273 }
1274 }
1275
1276 /* Copy the data back */
1277 RtlMoveMemory(LocalCaptureBuffer, RemoteCaptureBuffer, RemoteCaptureBuffer->Size);
1278
1279 /* Free our allocated buffer */
1280 RtlFreeHeap(CsrHeap, 0, RemoteCaptureBuffer);
1281 }
1282
1283
1284 /*++
1285 * @name CsrValidateMessageBuffer
1286 * @implemented NT5.1
1287 *
1288 * The CsrValidateMessageBuffer routine validates a captured message buffer
1289 * present in the CSR Api Message
1290 *
1291 * @param ApiMessage
1292 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1293 *
1294 * @param Buffer
1295 * Pointer to the message buffer to validate.
1296 *
1297 * @param ElementCount
1298 * Number of elements contained in the message buffer.
1299 *
1300 * @param ElementSize
1301 * Size of each element.
1302 *
1303 * @return TRUE if validation suceeded, FALSE otherwise.
1304 *
1305 * @remarks None.
1306 *
1307 *--*/
1308 BOOLEAN
1309 NTAPI
1310 CsrValidateMessageBuffer(IN PCSR_API_MESSAGE ApiMessage,
1311 IN PVOID *Buffer,
1312 IN ULONG ElementCount,
1313 IN ULONG ElementSize)
1314 {
1315 PCSR_CAPTURE_BUFFER CaptureBuffer = ApiMessage->CsrCaptureData;
1316 // SIZE_T BufferDistance = (ULONG_PTR)Buffer - (ULONG_PTR)ApiMessage;
1317 ULONG i;
1318
1319 /*
1320 * Check whether we have a valid buffer pointer, elements
1321 * of non-trivial size and that we don't overflow.
1322 */
1323 if (!Buffer || ElementSize == 0 ||
1324 (ULONGLONG)ElementCount * ElementSize > (ULONGLONG)0xFFFFFFFF)
1325 {
1326 return FALSE;
1327 }
1328
1329 /* Check if didn't get a buffer and there aren't any arguments to check */
1330 // if (!*Buffer && (ElementCount * ElementSize == 0))
1331 if (!*Buffer && ElementCount == 0) // Here ElementSize != 0 therefore only ElementCount can be == 0
1332 return TRUE;
1333
1334 /* Check if we have no capture buffer */
1335 if (!CaptureBuffer)
1336 {
1337 /*
1338 * In this case, check only the Process ID
1339 * and if there is a match, we succeed.
1340 */
1341 if (NtCurrentTeb()->ClientId.UniqueProcess ==
1342 ApiMessage->Header.ClientId.UniqueProcess)
1343 {
1344 return TRUE;
1345 }
1346 }
1347 else
1348 {
1349 /* Make sure that there is still space left in the buffer */
1350 if ((CaptureBuffer->Size - (ULONG_PTR)*Buffer + (ULONG_PTR)CaptureBuffer) >=
1351 (ElementCount * ElementSize))
1352 {
1353 for (i = 0 ; i < CaptureBuffer->PointerCount ; ++i)
1354 {
1355 /*
1356 * If the pointer offset is in fact equal to the
1357 * real address of the buffer then it's OK.
1358 */
1359 if (CaptureBuffer->PointerOffsetsArray[i] == (ULONG_PTR)Buffer /* BufferDistance + (ULONG_PTR)ApiMessage */)
1360 {
1361 return TRUE;
1362 }
1363 }
1364 }
1365 }
1366
1367 /* Failure */
1368 DPRINT1("CSRSRV: Bad message buffer %p\n", ApiMessage);
1369 DbgBreakPoint();
1370 return FALSE;
1371 }
1372
1373 /*** This is what we have in consrv/server.c ***
1374
1375 /\* Ensure that a captured buffer is safe to access *\/
1376 BOOL FASTCALL
1377 Win32CsrValidateBuffer(PCSR_PROCESS ProcessData, PVOID Buffer,
1378 SIZE_T NumElements, SIZE_T ElementSize)
1379 {
1380 /\* Check that the following conditions are true:
1381 * 1. The start of the buffer is somewhere within the process's
1382 * shared memory section view.
1383 * 2. The remaining space in the view is at least as large as the buffer.
1384 * (NB: Please don't try to "optimize" this by using multiplication
1385 * instead of division; remember that 2147483648 * 2 = 0.)
1386 * 3. The buffer is DWORD-aligned.
1387 *\/
1388 ULONG_PTR Offset = (BYTE *)Buffer - (BYTE *)ProcessData->ClientViewBase;
1389 if (Offset >= ProcessData->ClientViewBounds
1390 || NumElements > (ProcessData->ClientViewBounds - Offset) / ElementSize
1391 || (Offset & (sizeof(DWORD) - 1)) != 0)
1392 {
1393 DPRINT1("Invalid buffer %p(%u*%u); section view is %p(%u)\n",
1394 Buffer, NumElements, ElementSize,
1395 ProcessData->ClientViewBase, ProcessData->ClientViewBounds);
1396 return FALSE;
1397 }
1398 return TRUE;
1399 }
1400
1401 ***********************************************/
1402
1403 /*++
1404 * @name CsrValidateMessageString
1405 * @implemented NT5.1
1406 *
1407 * The CsrValidateMessageString validates a captured Wide-Character String
1408 * present in a CSR API Message.
1409 *
1410 * @param ApiMessage
1411 * Pointer to the CSR API Message containing the CSR Capture Buffer.
1412 *
1413 * @param MessageString
1414 * Pointer to the buffer containing the string to validate.
1415 *
1416 * @return TRUE if validation suceeded, FALSE otherwise.
1417 *
1418 * @remarks None.
1419 *
1420 *--*/
1421 BOOLEAN
1422 NTAPI
1423 CsrValidateMessageString(IN PCSR_API_MESSAGE ApiMessage,
1424 IN LPWSTR *MessageString)
1425 {
1426 if (MessageString)
1427 {
1428 return CsrValidateMessageBuffer(ApiMessage,
1429 (PVOID*)MessageString,
1430 wcslen(*MessageString) + 1,
1431 sizeof(WCHAR));
1432 }
1433 else
1434 {
1435 return FALSE;
1436 }
1437 }
1438
1439 /* EOF */