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