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