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 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 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 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 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 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 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 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 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 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 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 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