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