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