1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS Client/Server Runtime SubSystem 4 * FILE: subsystems/win32/csrsrv/procsup.c 5 * PURPOSE: CSR Server DLL Process Management 6 * PROGRAMMERS: ReactOS Portable Systems Group 7 * Alex Ionescu (alex@relsoft.net) 8 */ 9 10 /* INCLUDES *******************************************************************/ 11 12 #include <srv.h> 13 14 #include <winuser.h> 15 16 #define NDEBUG 17 #include <debug.h> 18 19 /* GLOBALS ********************************************************************/ 20 21 RTL_CRITICAL_SECTION CsrProcessLock; 22 PCSR_PROCESS CsrRootProcess = NULL; 23 SECURITY_QUALITY_OF_SERVICE CsrSecurityQos = 24 { 25 sizeof(SECURITY_QUALITY_OF_SERVICE), 26 SecurityImpersonation, 27 SECURITY_STATIC_TRACKING, 28 FALSE 29 }; 30 ULONG CsrProcessSequenceCount = 5; 31 extern ULONG CsrTotalPerProcessDataLength; 32 33 34 /* PRIVATE FUNCTIONS **********************************************************/ 35 36 /*++ 37 * @name CsrSetToNormalPriority 38 * 39 * The CsrSetToNormalPriority routine sets the current NT Process' 40 * priority to the normal priority for CSR Processes. 41 * 42 * @param None. 43 * 44 * @return None. 45 * 46 * @remarks The "Normal" Priority corresponds to the Normal Foreground 47 * Priority (9) plus a boost of 4. 48 * 49 *--*/ 50 VOID 51 NTAPI 52 CsrSetToNormalPriority(VOID) 53 { 54 KPRIORITY BasePriority = PROCESS_PRIORITY_NORMAL_FOREGROUND + 4; 55 56 /* Set the base priority */ 57 NtSetInformationProcess(NtCurrentProcess(), 58 ProcessBasePriority, 59 &BasePriority, 60 sizeof(BasePriority)); 61 } 62 63 /*++ 64 * @name CsrSetToShutdownPriority 65 * 66 * The CsrSetToShutdownPriority routine sets the current NT Process' 67 * priority to the boosted priority for CSR Processes doing shutdown, 68 * acquiring also the required Increase Base Priority privilege. 69 * 70 * @param None. 71 * 72 * @return None. 73 * 74 * @remarks The "Shutdown" Priority corresponds to the Normal Foreground 75 * Priority (9) plus a boost of 6. 76 * 77 *--*/ 78 VOID 79 NTAPI 80 CsrSetToShutdownPriority(VOID) 81 { 82 KPRIORITY BasePriority = PROCESS_PRIORITY_NORMAL_FOREGROUND + 6; 83 BOOLEAN Old; 84 85 /* Get the Increase Base Priority privilege */ 86 if (NT_SUCCESS(RtlAdjustPrivilege(SE_INC_BASE_PRIORITY_PRIVILEGE, 87 TRUE, 88 FALSE, 89 &Old))) 90 { 91 /* Set the base priority */ 92 NtSetInformationProcess(NtCurrentProcess(), 93 ProcessBasePriority, 94 &BasePriority, 95 sizeof(BasePriority)); 96 } 97 } 98 99 /*++ 100 * @name CsrProcessRefcountZero 101 * 102 * The CsrProcessRefcountZero routine is executed when a CSR Process has lost 103 * all its active references. It removes and de-allocates the CSR Process. 104 * 105 * @param CsrProcess 106 * Pointer to the CSR Process that is to be deleted. 107 * 108 * @return None. 109 * 110 * @remarks Do not call this routine. It is reserved for the internal 111 * thread management routines when a CSR Process has lost all 112 * its references. 113 * 114 * This routine is called with the Process Lock held. 115 * 116 *--*/ 117 VOID 118 NTAPI 119 CsrProcessRefcountZero(IN PCSR_PROCESS CsrProcess) 120 { 121 ASSERT(ProcessStructureListLocked()); 122 123 /* Remove the Process from the list */ 124 CsrRemoveProcess(CsrProcess); 125 126 /* Check if there's a session */ 127 if (CsrProcess->NtSession) 128 { 129 /* Dereference the Session */ 130 CsrDereferenceNtSession(CsrProcess->NtSession, STATUS_SUCCESS); 131 } 132 133 /* Close the Client Port if there is one */ 134 if (CsrProcess->ClientPort) NtClose(CsrProcess->ClientPort); 135 136 /* Close the process handle */ 137 NtClose(CsrProcess->ProcessHandle); 138 139 /* Free the Process Object */ 140 CsrDeallocateProcess(CsrProcess); 141 } 142 143 /*++ 144 * @name CsrLockedDereferenceProcess 145 * 146 * The CsrLockedDereferenceProcess dereferences a CSR Process while the 147 * Process Lock is already being held. 148 * 149 * @param CsrProcess 150 * Pointer to the CSR Process to be dereferenced. 151 * 152 * @return None. 153 * 154 * @remarks This routine will return with the Process Lock held. 155 * 156 *--*/ 157 VOID 158 NTAPI 159 CsrLockedDereferenceProcess(PCSR_PROCESS CsrProcess) 160 { 161 LONG LockCount; 162 163 /* Decrease reference count */ 164 LockCount = --CsrProcess->ReferenceCount; 165 ASSERT(LockCount >= 0); 166 if (LockCount == 0) 167 { 168 /* Call the generic cleanup code */ 169 DPRINT1("Should kill process: %p\n", CsrProcess); 170 CsrProcessRefcountZero(CsrProcess); 171 /* Acquire the lock again, it was released in CsrProcessRefcountZero */ 172 CsrAcquireProcessLock(); 173 } 174 } 175 176 /*++ 177 * @name CsrAllocateProcess 178 * @implemented NT4 179 * 180 * The CsrAllocateProcess routine allocates a new CSR Process object. 181 * 182 * @return Pointer to the newly allocated CSR Process. 183 * 184 * @remarks None. 185 * 186 *--*/ 187 PCSR_PROCESS 188 NTAPI 189 CsrAllocateProcess(VOID) 190 { 191 PCSR_PROCESS CsrProcess; 192 ULONG TotalSize; 193 194 /* Calculate the amount of memory this should take */ 195 TotalSize = sizeof(CSR_PROCESS) + 196 (CSR_SERVER_DLL_MAX * sizeof(PVOID)) + 197 CsrTotalPerProcessDataLength; 198 199 /* Allocate a Process */ 200 CsrProcess = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, TotalSize); 201 if (!CsrProcess) return NULL; 202 203 /* Handle the Sequence Number and protect against overflow */ 204 CsrProcess->SequenceNumber = CsrProcessSequenceCount++; 205 if (CsrProcessSequenceCount < 5) CsrProcessSequenceCount = 5; 206 207 /* Increase the reference count */ 208 CsrLockedReferenceProcess(CsrProcess); 209 210 /* Initialize the Thread List */ 211 InitializeListHead(&CsrProcess->ThreadList); 212 213 /* Return the Process */ 214 return CsrProcess; 215 } 216 217 /*++ 218 * @name CsrLockedReferenceProcess 219 * 220 * The CsrLockedReferenceProcess references a CSR Process while the 221 * Process Lock is already being held. 222 * 223 * @param CsrProcess 224 * Pointer to the CSR Process to be referenced. 225 * 226 * @return None. 227 * 228 * @remarks This routine will return with the Process Lock held. 229 * 230 *--*/ 231 VOID 232 NTAPI 233 CsrLockedReferenceProcess(IN PCSR_PROCESS CsrProcess) 234 { 235 /* Increment the reference count */ 236 ++CsrProcess->ReferenceCount; 237 } 238 239 /*++ 240 * @name CsrInitializeProcessStructure 241 * @implemented NT4 242 * 243 * The CsrInitializeProcessStructure routine sets up support for CSR Processes 244 * and CSR Threads by initializing our own CSR Root Process. 245 * 246 * @param None. 247 * 248 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise. 249 * 250 * @remarks None. 251 * 252 *--*/ 253 NTSTATUS 254 NTAPI 255 CsrInitializeProcessStructure(VOID) 256 { 257 NTSTATUS Status; 258 ULONG i; 259 260 /* Initialize the Lock */ 261 Status = RtlInitializeCriticalSection(&CsrProcessLock); 262 if (!NT_SUCCESS(Status)) return Status; 263 264 /* Set up the Root Process */ 265 CsrRootProcess = CsrAllocateProcess(); 266 if (!CsrRootProcess) return STATUS_NO_MEMORY; 267 268 /* Set up the minimal information for it */ 269 InitializeListHead(&CsrRootProcess->ListLink); 270 CsrRootProcess->ProcessHandle = (HANDLE)-1; 271 CsrRootProcess->ClientId = NtCurrentTeb()->ClientId; 272 273 /* Initialize the Thread Hash List */ 274 for (i = 0; i < NUMBER_THREAD_HASH_BUCKETS; i++) InitializeListHead(&CsrThreadHashTable[i]); 275 276 /* Initialize the Wait Lock */ 277 return RtlInitializeCriticalSection(&CsrWaitListsLock); 278 } 279 280 /*++ 281 * @name CsrDeallocateProcess 282 * 283 * The CsrDeallocateProcess frees the memory associated with a CSR Process. 284 * 285 * @param CsrProcess 286 * Pointer to the CSR Process to be freed. 287 * 288 * @return None. 289 * 290 * @remarks Do not call this routine. It is reserved for the internal 291 * thread management routines when a CSR Process has been cleanly 292 * dereferenced and killed. 293 * 294 *--*/ 295 VOID 296 NTAPI 297 CsrDeallocateProcess(IN PCSR_PROCESS CsrProcess) 298 { 299 /* Free the process object from the heap */ 300 RtlFreeHeap(CsrHeap, 0, CsrProcess); 301 } 302 303 /*++ 304 * @name CsrRemoveProcess 305 * 306 * The CsrRemoveProcess function undoes a CsrInsertProcess operation and 307 * removes the CSR Process from the Process List and notifies Server DLLs 308 * of this removal. 309 * 310 * @param CsrProcess 311 * Pointer to the CSR Process to remove. 312 * 313 * @return None. 314 * 315 * @remarks None. 316 * 317 *--*/ 318 VOID 319 NTAPI 320 CsrRemoveProcess(IN PCSR_PROCESS CsrProcess) 321 { 322 PCSR_SERVER_DLL ServerDll; 323 ULONG i; 324 ASSERT(ProcessStructureListLocked()); 325 326 /* Remove us from the Process List */ 327 RemoveEntryList(&CsrProcess->ListLink); 328 329 /* Release the lock */ 330 CsrReleaseProcessLock(); 331 332 /* Loop every Server DLL */ 333 for (i = 0; i < CSR_SERVER_DLL_MAX; i++) 334 { 335 /* Get the Server DLL */ 336 ServerDll = CsrLoadedServerDll[i]; 337 338 /* Check if it's valid and if it has a Disconnect Callback */ 339 if (ServerDll && ServerDll->DisconnectCallback) 340 { 341 /* Call it */ 342 ServerDll->DisconnectCallback(CsrProcess); 343 } 344 } 345 } 346 347 /*++ 348 * @name CsrInsertProcess 349 * 350 * The CsrInsertProcess routine inserts a CSR Process into the Process List 351 * and notifies Server DLLs of the creation of a new CSR Process. 352 * 353 * @param ParentProcess 354 * Optional pointer to the Parent Process creating this CSR Process. 355 * 356 * @param CsrProcess 357 * Pointer to the CSR Process which is to be inserted. 358 * 359 * @return None. 360 * 361 * @remarks None. 362 * 363 *--*/ 364 VOID 365 NTAPI 366 CsrInsertProcess(IN PCSR_PROCESS ParentProcess OPTIONAL, 367 IN PCSR_PROCESS CsrProcess) 368 { 369 PCSR_SERVER_DLL ServerDll; 370 ULONG i; 371 ASSERT(ProcessStructureListLocked()); 372 373 /* Insert it into the Root List */ 374 InsertTailList(&CsrRootProcess->ListLink, &CsrProcess->ListLink); 375 376 /* Notify the Server DLLs */ 377 for (i = 0; i < CSR_SERVER_DLL_MAX; i++) 378 { 379 /* Get the current Server DLL */ 380 ServerDll = CsrLoadedServerDll[i]; 381 382 /* Make sure it's valid and that it has callback */ 383 if (ServerDll && ServerDll->NewProcessCallback) 384 { 385 ServerDll->NewProcessCallback(ParentProcess, CsrProcess); 386 } 387 } 388 } 389 390 391 /* PUBLIC FUNCTIONS ***********************************************************/ 392 393 /*++ 394 * @name CsrCreateProcess 395 * @implemented NT4 396 * 397 * The CsrCreateProcess routine creates a CSR Process object for an NT Process. 398 * 399 * @param hProcess 400 * Handle to an existing NT Process to which to associate this 401 * CSR Process. 402 * 403 * @param hThread 404 * Handle to an existing NT Thread to which to create its 405 * corresponding CSR Thread for this CSR Process. 406 * 407 * @param ClientId 408 * Pointer to the Client ID structure of the NT Process to associate 409 * with this CSR Process. 410 * 411 * @param NtSession 412 * @param Flags 413 * @param DebugCid 414 * 415 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise. 416 * 417 * @remarks None. 418 * 419 *--*/ 420 NTSTATUS 421 NTAPI 422 CsrCreateProcess(IN HANDLE hProcess, 423 IN HANDLE hThread, 424 IN PCLIENT_ID ClientId, 425 IN PCSR_NT_SESSION NtSession, 426 IN ULONG Flags, 427 IN PCLIENT_ID DebugCid) 428 { 429 PCSR_THREAD CurrentThread = CsrGetClientThread(); 430 CLIENT_ID CurrentCid; 431 PCSR_PROCESS CurrentProcess; 432 PCSR_SERVER_DLL ServerDll; 433 PVOID ProcessData; 434 ULONG i; 435 PCSR_PROCESS CsrProcess; 436 NTSTATUS Status; 437 PCSR_THREAD CsrThread; 438 KERNEL_USER_TIMES KernelTimes; 439 440 /* Get the current CID and lock Processes */ 441 CurrentCid = CurrentThread->ClientId; 442 CsrAcquireProcessLock(); 443 444 /* Get the current CSR Thread */ 445 CurrentThread = CsrLocateThreadByClientId(&CurrentProcess, &CurrentCid); 446 if (!CurrentThread) 447 { 448 /* We've failed to locate the thread */ 449 CsrReleaseProcessLock(); 450 return STATUS_THREAD_IS_TERMINATING; 451 } 452 453 /* Allocate a new Process Object */ 454 CsrProcess = CsrAllocateProcess(); 455 if (!CsrProcess) 456 { 457 /* Couldn't allocate Process */ 458 CsrReleaseProcessLock(); 459 return STATUS_NO_MEMORY; 460 } 461 462 /* Inherit the Process Data */ 463 CurrentProcess = CurrentThread->Process; 464 ProcessData = &CsrProcess->ServerData[CSR_SERVER_DLL_MAX]; 465 for (i = 0; i < CSR_SERVER_DLL_MAX; i++) 466 { 467 /* Get the current Server */ 468 ServerDll = CsrLoadedServerDll[i]; 469 470 /* Check if the DLL is Loaded and has Per Process Data */ 471 if (ServerDll && ServerDll->SizeOfProcessData) 472 { 473 /* Set the pointer */ 474 CsrProcess->ServerData[i] = ProcessData; 475 476 /* Copy the Data */ 477 RtlMoveMemory(ProcessData, 478 CurrentProcess->ServerData[i], 479 ServerDll->SizeOfProcessData); 480 481 /* Update next data pointer */ 482 ProcessData = (PVOID)((ULONG_PTR)ProcessData + 483 ServerDll->SizeOfProcessData); 484 } 485 else 486 { 487 /* No data for this Server */ 488 CsrProcess->ServerData[i] = NULL; 489 } 490 } 491 492 /* Set the Exception Port for us */ 493 Status = NtSetInformationProcess(hProcess, 494 ProcessExceptionPort, 495 &CsrApiPort, 496 sizeof(CsrApiPort)); 497 if (!NT_SUCCESS(Status)) 498 { 499 /* Failed */ 500 CsrDeallocateProcess(CsrProcess); 501 CsrReleaseProcessLock(); 502 return STATUS_NO_MEMORY; 503 } 504 505 /* Check if CreateProcess got CREATE_NEW_PROCESS_GROUP */ 506 if (Flags & CsrProcessCreateNewGroup) 507 { 508 /* 509 * We create the process group leader of a new process group, therefore 510 * its process group ID and sequence number are its own ones. 511 */ 512 CsrProcess->ProcessGroupId = HandleToUlong(ClientId->UniqueProcess); 513 CsrProcess->ProcessGroupSequence = CsrProcess->SequenceNumber; 514 } 515 else 516 { 517 /* Inherit the process group ID and sequence number from the current process */ 518 CsrProcess->ProcessGroupId = CurrentProcess->ProcessGroupId; 519 CsrProcess->ProcessGroupSequence = CurrentProcess->ProcessGroupSequence; 520 } 521 522 /* Check if this is a console process */ 523 if (Flags & CsrProcessIsConsoleApp) CsrProcess->Flags |= CsrProcessIsConsoleApp; 524 525 /* Mask out non-debug flags */ 526 Flags &= ~(CsrProcessIsConsoleApp | CsrProcessCreateNewGroup | CsrProcessPriorityFlags); 527 528 /* Check if every process will be debugged */ 529 if (!(Flags) && (CurrentProcess->DebugFlags & CsrDebugProcessChildren)) 530 { 531 /* Pass it on to the current process */ 532 CsrProcess->DebugFlags = CsrDebugProcessChildren; 533 CsrProcess->DebugCid = CurrentProcess->DebugCid; 534 } 535 536 /* Check if Debugging was used on this process */ 537 if ((Flags & (CsrDebugOnlyThisProcess | CsrDebugProcessChildren)) && (DebugCid)) 538 { 539 /* Save the debug flag used */ 540 CsrProcess->DebugFlags = Flags; 541 542 /* Save the CID */ 543 CsrProcess->DebugCid = *DebugCid; 544 } 545 546 /* Check if Debugging is enabled */ 547 if (CsrProcess->DebugFlags) 548 { 549 /* Set the Debug Port for us */ 550 Status = NtSetInformationProcess(hProcess, 551 ProcessDebugPort, 552 &CsrApiPort, 553 sizeof(CsrApiPort)); 554 ASSERT(NT_SUCCESS(Status)); 555 if (!NT_SUCCESS(Status)) 556 { 557 /* Failed */ 558 CsrDeallocateProcess(CsrProcess); 559 CsrReleaseProcessLock(); 560 return STATUS_NO_MEMORY; 561 } 562 } 563 564 /* Get the Thread Create Time */ 565 Status = NtQueryInformationThread(hThread, 566 ThreadTimes, 567 &KernelTimes, 568 sizeof(KernelTimes), 569 NULL); 570 if (!NT_SUCCESS(Status)) 571 { 572 /* Failed */ 573 CsrDeallocateProcess(CsrProcess); 574 CsrReleaseProcessLock(); 575 return STATUS_NO_MEMORY; 576 } 577 578 /* Allocate a CSR Thread Structure */ 579 CsrThread = CsrAllocateThread(CsrProcess); 580 if (!CsrThread) 581 { 582 /* Failed */ 583 CsrDeallocateProcess(CsrProcess); 584 CsrReleaseProcessLock(); 585 return STATUS_NO_MEMORY; 586 } 587 588 /* Save the data we have */ 589 CsrThread->CreateTime = KernelTimes.CreateTime; 590 CsrThread->ClientId = *ClientId; 591 CsrThread->ThreadHandle = hThread; 592 ProtectHandle(hThread); 593 CsrThread->Flags = 0; 594 595 /* Insert the Thread into the Process */ 596 Status = CsrInsertThread(CsrProcess, CsrThread); 597 if (!NT_SUCCESS(Status)) 598 { 599 /* Bail out */ 600 CsrDeallocateProcess(CsrProcess); 601 CsrDeallocateThread(CsrThread); 602 CsrReleaseProcessLock(); 603 return Status; 604 } 605 606 /* Reference the session */ 607 CsrReferenceNtSession(NtSession); 608 CsrProcess->NtSession = NtSession; 609 610 /* Setup Process Data */ 611 CsrProcess->ClientId = *ClientId; 612 CsrProcess->ProcessHandle = hProcess; 613 CsrProcess->ShutdownLevel = 0x280; 614 615 /* Set the priority to Background */ 616 CsrSetBackgroundPriority(CsrProcess); 617 618 /* Insert the Process */ 619 CsrInsertProcess(CurrentProcess, CsrProcess); 620 621 /* Release lock and return */ 622 CsrReleaseProcessLock(); 623 return Status; 624 } 625 626 /*++ 627 * @name CsrDebugProcess 628 * @implemented NT4 629 * 630 * The CsrDebugProcess routine is deprecated in NT 5.1 and higher. It is 631 * exported only for compatibility with older CSR Server DLLs. 632 * 633 * @param CsrProcess 634 * Deprecated. 635 * 636 * @return Deprecated 637 * 638 * @remarks Deprecated. 639 * 640 *--*/ 641 NTSTATUS 642 NTAPI 643 CsrDebugProcess(IN PCSR_PROCESS CsrProcess) 644 { 645 /* CSR does not handle debugging anymore */ 646 DPRINT("CSRSRV: %s(0x%p) called\n", __FUNCTION__, CsrProcess); 647 return STATUS_UNSUCCESSFUL; 648 } 649 650 /*++ 651 * @name CsrDebugProcessStop 652 * @implemented NT4 653 * 654 * The CsrDebugProcessStop routine is deprecated in NT 5.1 and higher. It is 655 * exported only for compatibility with older CSR Server DLLs. 656 * 657 * @param CsrProcess 658 * Deprecated. 659 * 660 * @return Deprecated 661 * 662 * @remarks Deprecated. 663 * 664 *--*/ 665 NTSTATUS 666 NTAPI 667 CsrDebugProcessStop(IN PCSR_PROCESS CsrProcess) 668 { 669 /* CSR does not handle debugging anymore */ 670 DPRINT("CSRSRV: %s(0x%p) called\n", __FUNCTION__, CsrProcess); 671 return STATUS_UNSUCCESSFUL; 672 } 673 674 /*++ 675 * @name CsrDereferenceProcess 676 * @implemented NT4 677 * 678 * The CsrDereferenceProcess routine removes a reference from a CSR Process. 679 * 680 * @param CsrThread 681 * Pointer to the CSR Process to dereference. 682 * 683 * @return None. 684 * 685 * @remarks If the reference count has reached zero (ie: the CSR Process has 686 * no more active references), it will be deleted. 687 * 688 *--*/ 689 VOID 690 NTAPI 691 CsrDereferenceProcess(IN PCSR_PROCESS CsrProcess) 692 { 693 LONG LockCount; 694 695 /* Acquire process lock */ 696 CsrAcquireProcessLock(); 697 698 /* Decrease reference count */ 699 LockCount = --CsrProcess->ReferenceCount; 700 ASSERT(LockCount >= 0); 701 if (LockCount == 0) 702 { 703 /* Call the generic cleanup code */ 704 CsrProcessRefcountZero(CsrProcess); 705 } 706 else 707 { 708 /* Just release the lock */ 709 CsrReleaseProcessLock(); 710 } 711 } 712 713 /*++ 714 * @name CsrDestroyProcess 715 * @implemented NT4 716 * 717 * The CsrDestroyProcess routine destroys the CSR Process corresponding to 718 * a given Client ID. 719 * 720 * @param Cid 721 * Pointer to the Client ID Structure corresponding to the CSR 722 * Process which is about to be destroyed. 723 * 724 * @param ExitStatus 725 * Unused. 726 * 727 * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING 728 * if the CSR Process is already terminating. 729 * 730 * @remarks None. 731 * 732 *--*/ 733 NTSTATUS 734 NTAPI 735 CsrDestroyProcess(IN PCLIENT_ID Cid, 736 IN NTSTATUS ExitStatus) 737 { 738 PCSR_THREAD CsrThread; 739 PCSR_PROCESS CsrProcess; 740 CLIENT_ID ClientId = *Cid; 741 PLIST_ENTRY NextEntry; 742 743 /* Acquire lock */ 744 CsrAcquireProcessLock(); 745 746 /* Find the thread */ 747 CsrThread = CsrLocateThreadByClientId(&CsrProcess, &ClientId); 748 749 /* Make sure we got one back, and that it's not already gone */ 750 if (!(CsrThread) || (CsrProcess->Flags & CsrProcessTerminating)) 751 { 752 /* Release the lock and return failure */ 753 CsrReleaseProcessLock(); 754 return STATUS_THREAD_IS_TERMINATING; 755 } 756 757 /* Set the terminated flag */ 758 CsrProcess->Flags |= CsrProcessTerminating; 759 760 /* Get the List Pointers */ 761 NextEntry = CsrProcess->ThreadList.Flink; 762 while (NextEntry != &CsrProcess->ThreadList) 763 { 764 /* Get the current thread entry */ 765 CsrThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link); 766 767 /* Move to the next entry */ 768 NextEntry = NextEntry->Flink; 769 770 /* Make sure the thread isn't already dead */ 771 if (CsrThread->Flags & CsrThreadTerminated) 772 { 773 /* Go the the next thread */ 774 continue; 775 } 776 777 /* Set the Terminated flag */ 778 CsrThread->Flags |= CsrThreadTerminated; 779 780 /* Acquire the Wait Lock */ 781 CsrAcquireWaitLock(); 782 783 /* Do we have an active wait block? */ 784 if (CsrThread->WaitBlock) 785 { 786 /* Notify waiters of termination */ 787 CsrNotifyWaitBlock(CsrThread->WaitBlock, 788 NULL, 789 NULL, 790 NULL, 791 CsrProcessTerminating, 792 TRUE); 793 } 794 795 /* Release the Wait Lock */ 796 CsrReleaseWaitLock(); 797 798 /* Dereference the thread */ 799 CsrLockedDereferenceThread(CsrThread); 800 } 801 802 /* Release the Process Lock and return success */ 803 CsrReleaseProcessLock(); 804 return STATUS_SUCCESS; 805 } 806 807 /*++ 808 * @name CsrGetProcessLuid 809 * @implemented NT4 810 * 811 * The CsrGetProcessLuid routine gets the LUID of the given process. 812 * 813 * @param hProcess 814 * Optional handle to the process whose LUID should be returned. 815 * 816 * @param Luid 817 * Pointer to a LUID Pointer which will receive the CSR Process' LUID. 818 * 819 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise. 820 * 821 * @remarks If hProcess is not supplied, then the current thread's token will 822 * be used. If that too is missing, then the current process' token 823 * will be used. 824 * 825 *--*/ 826 NTSTATUS 827 NTAPI 828 CsrGetProcessLuid(IN HANDLE hProcess OPTIONAL, 829 OUT PLUID Luid) 830 { 831 HANDLE hToken = NULL; 832 NTSTATUS Status; 833 ULONG Length; 834 PTOKEN_STATISTICS TokenStats; 835 836 /* Check if we have a handle to a CSR Process */ 837 if (!hProcess) 838 { 839 /* We don't, so try opening the Thread's Token */ 840 Status = NtOpenThreadToken(NtCurrentThread(), 841 TOKEN_QUERY, 842 FALSE, 843 &hToken); 844 845 /* Check for success */ 846 if (!NT_SUCCESS(Status)) 847 { 848 /* If we got some other failure, then return and quit */ 849 if (Status != STATUS_NO_TOKEN) return Status; 850 851 /* We don't have a Thread Token, use a Process Token */ 852 hProcess = NtCurrentProcess(); 853 hToken = NULL; 854 } 855 } 856 857 /* Check if we have a token by now */ 858 if (!hToken) 859 { 860 /* No token yet, so open the Process Token */ 861 Status = NtOpenProcessToken(hProcess, 862 TOKEN_QUERY, 863 &hToken); 864 if (!NT_SUCCESS(Status)) 865 { 866 /* Still no token, return the error */ 867 return Status; 868 } 869 } 870 871 /* Now get the size we'll need for the Token Information */ 872 Status = NtQueryInformationToken(hToken, 873 TokenStatistics, 874 NULL, 875 0, 876 &Length); 877 if (Status != STATUS_BUFFER_TOO_SMALL) 878 { 879 /* Close the token and fail */ 880 NtClose(hToken); 881 return Status; 882 } 883 884 /* Allocate memory for the Token Info */ 885 if (!(TokenStats = RtlAllocateHeap(CsrHeap, 0, Length))) 886 { 887 /* Fail and close the token */ 888 NtClose(hToken); 889 return STATUS_NO_MEMORY; 890 } 891 892 /* Now query the information */ 893 Status = NtQueryInformationToken(hToken, 894 TokenStatistics, 895 TokenStats, 896 Length, 897 &Length); 898 899 /* Close the handle */ 900 NtClose(hToken); 901 902 /* Check for success */ 903 if (NT_SUCCESS(Status)) 904 { 905 /* Return the LUID */ 906 *Luid = TokenStats->AuthenticationId; 907 } 908 909 /* Free the query information */ 910 RtlFreeHeap(CsrHeap, 0, TokenStats); 911 912 /* Return the Status */ 913 return Status; 914 } 915 916 /*++ 917 * @name CsrImpersonateClient 918 * @implemented NT4 919 * 920 * The CsrImpersonateClient will impersonate the given CSR Thread. 921 * 922 * @param CsrThread 923 * Pointer to the CSR Thread to impersonate. 924 * 925 * @return TRUE if impersonation succeeded, FALSE otherwise. 926 * 927 * @remarks Impersonation can be recursive. 928 * 929 *--*/ 930 BOOLEAN 931 NTAPI 932 CsrImpersonateClient(IN PCSR_THREAD CsrThread) 933 { 934 NTSTATUS Status; 935 PCSR_THREAD CurrentThread = CsrGetClientThread(); 936 937 /* Use the current thread if none given */ 938 if (!CsrThread) CsrThread = CurrentThread; 939 940 /* Still no thread, something is wrong */ 941 if (!CsrThread) 942 { 943 /* Failure */ 944 return FALSE; 945 } 946 947 /* Make the call */ 948 Status = NtImpersonateThread(NtCurrentThread(), 949 CsrThread->ThreadHandle, 950 &CsrSecurityQos); 951 952 if (!NT_SUCCESS(Status)) 953 { 954 /* Failure */ 955 #ifdef CSR_DBG 956 DPRINT1("CSRSS: Can't impersonate client thread - Status = %lx\n", Status); 957 // if (Status != STATUS_BAD_IMPERSONATION_LEVEL) DbgBreakPoint(); 958 #endif 959 return FALSE; 960 } 961 962 /* Increase the impersonation count for the current thread */ 963 if (CurrentThread) ++CurrentThread->ImpersonationCount; 964 965 /* Return Success */ 966 return TRUE; 967 } 968 969 /*++ 970 * @name CsrLockProcessByClientId 971 * @implemented NT4 972 * 973 * The CsrLockProcessByClientId routine locks the CSR Process corresponding 974 * to the given Process ID and optionally returns it. 975 * 976 * @param Pid 977 * Process ID corresponding to the CSR Process which will be locked. 978 * 979 * @param CsrProcess 980 * Optional pointer to a CSR Process pointer which will hold the 981 * CSR Process corresponding to the given Process ID. 982 * 983 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise. 984 * 985 * @remarks Locking a CSR Process is defined as acquiring an extra 986 * reference to it and returning with the Process Lock held. 987 * 988 *--*/ 989 NTSTATUS 990 NTAPI 991 CsrLockProcessByClientId(IN HANDLE Pid, 992 OUT PCSR_PROCESS *CsrProcess) 993 { 994 PLIST_ENTRY NextEntry; 995 PCSR_PROCESS CurrentProcess = NULL; 996 NTSTATUS Status = STATUS_UNSUCCESSFUL; 997 998 /* Acquire the lock */ 999 CsrAcquireProcessLock(); 1000 1001 /* Assume failure */ 1002 ASSERT(CsrProcess != NULL); 1003 *CsrProcess = NULL; 1004 1005 /* Setup the List Pointers */ 1006 NextEntry = &CsrRootProcess->ListLink; 1007 do 1008 { 1009 /* Get the Process */ 1010 CurrentProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink); 1011 1012 /* Check for PID Match */ 1013 if (CurrentProcess->ClientId.UniqueProcess == Pid) 1014 { 1015 Status = STATUS_SUCCESS; 1016 break; 1017 } 1018 1019 /* Move to the next entry */ 1020 NextEntry = NextEntry->Flink; 1021 } while (NextEntry != &CsrRootProcess->ListLink); 1022 1023 /* Check if we didn't find it in the list */ 1024 if (!NT_SUCCESS(Status)) 1025 { 1026 /* Nothing found, release the lock */ 1027 CsrReleaseProcessLock(); 1028 } 1029 else 1030 { 1031 /* Lock the found process and return it */ 1032 CsrLockedReferenceProcess(CurrentProcess); 1033 *CsrProcess = CurrentProcess; 1034 } 1035 1036 /* Return the result */ 1037 return Status; 1038 } 1039 1040 /*++ 1041 * @name CsrRevertToSelf 1042 * @implemented NT4 1043 * 1044 * The CsrRevertToSelf routine will attempt to remove an active impersonation. 1045 * 1046 * @param None. 1047 * 1048 * @return TRUE if the reversion was succesful, FALSE otherwise. 1049 * 1050 * @remarks Impersonation can be recursive; as such, the impersonation token 1051 * will only be deleted once the CSR Thread's impersonation count 1052 * has reached zero. 1053 * 1054 *--*/ 1055 BOOLEAN 1056 NTAPI 1057 CsrRevertToSelf(VOID) 1058 { 1059 NTSTATUS Status; 1060 PCSR_THREAD CurrentThread = CsrGetClientThread(); 1061 HANDLE ImpersonationToken = NULL; 1062 1063 /* Check if we have a Current Thread */ 1064 if (CurrentThread) 1065 { 1066 /* Make sure impersonation is on */ 1067 if (!CurrentThread->ImpersonationCount) 1068 { 1069 DPRINT1("CSRSS: CsrRevertToSelf called while not impersonating\n"); 1070 // DbgBreakPoint(); 1071 return FALSE; 1072 } 1073 else if ((--CurrentThread->ImpersonationCount) > 0) 1074 { 1075 /* Success; impersonation count decreased but still not zero */ 1076 return TRUE; 1077 } 1078 } 1079 1080 /* Impersonation has been totally removed, revert to ourselves */ 1081 Status = NtSetInformationThread(NtCurrentThread(), 1082 ThreadImpersonationToken, 1083 &ImpersonationToken, 1084 sizeof(ImpersonationToken)); 1085 1086 /* Return TRUE or FALSE */ 1087 return NT_SUCCESS(Status); 1088 } 1089 1090 /*++ 1091 * @name CsrSetBackgroundPriority 1092 * @implemented NT4 1093 * 1094 * The CsrSetBackgroundPriority routine sets the priority for the given CSR 1095 * Process as a Background priority. 1096 * 1097 * @param CsrProcess 1098 * Pointer to the CSR Process whose priority will be modified. 1099 * 1100 * @return None. 1101 * 1102 * @remarks None. 1103 * 1104 *--*/ 1105 VOID 1106 NTAPI 1107 CsrSetBackgroundPriority(IN PCSR_PROCESS CsrProcess) 1108 { 1109 PROCESS_FOREGROUND_BACKGROUND ProcessPriority; 1110 1111 /* Set the Foreground bit off */ 1112 ProcessPriority.Foreground = FALSE; 1113 1114 /* Set the new priority */ 1115 NtSetInformationProcess(CsrProcess->ProcessHandle, 1116 ProcessForegroundInformation, 1117 &ProcessPriority, 1118 sizeof(ProcessPriority)); 1119 } 1120 1121 /*++ 1122 * @name CsrSetForegroundPriority 1123 * @implemented NT4 1124 * 1125 * The CsrSetForegroundPriority routine sets the priority for the given CSR 1126 * Process as a Foreground priority. 1127 * 1128 * @param CsrProcess 1129 * Pointer to the CSR Process whose priority will be modified. 1130 * 1131 * @return None. 1132 * 1133 * @remarks None. 1134 * 1135 *--*/ 1136 VOID 1137 NTAPI 1138 CsrSetForegroundPriority(IN PCSR_PROCESS CsrProcess) 1139 { 1140 PROCESS_FOREGROUND_BACKGROUND ProcessPriority; 1141 1142 /* Set the Foreground bit on */ 1143 ProcessPriority.Foreground = TRUE; 1144 1145 /* Set the new priority */ 1146 NtSetInformationProcess(CsrProcess->ProcessHandle, 1147 ProcessForegroundInformation, 1148 &ProcessPriority, 1149 sizeof(ProcessPriority)); 1150 } 1151 1152 /*++ 1153 * @name FindProcessForShutdown 1154 * 1155 * The FindProcessForShutdown routine returns a CSR Process which is ready 1156 * to be shutdown, and sets the appropriate shutdown flags for it. 1157 * 1158 * @param CallerLuid 1159 * Pointer to the LUID of the CSR Process calling this routine. 1160 * 1161 * @return Pointer to a CSR Process which is ready to be shutdown. 1162 * 1163 * @remarks None. 1164 * 1165 *--*/ 1166 PCSR_PROCESS 1167 NTAPI 1168 FindProcessForShutdown(IN PLUID CallerLuid) 1169 { 1170 PCSR_PROCESS CsrProcess, ReturnCsrProcess = NULL; 1171 PCSR_THREAD CsrThread; 1172 NTSTATUS Status; 1173 ULONG Level = 0; 1174 LUID ProcessLuid; 1175 LUID SystemLuid = SYSTEM_LUID; 1176 PLIST_ENTRY NextEntry; 1177 1178 /* Set the List Pointers */ 1179 NextEntry = CsrRootProcess->ListLink.Flink; 1180 while (NextEntry != &CsrRootProcess->ListLink) 1181 { 1182 /* Get the process */ 1183 CsrProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink); 1184 1185 /* Move to the next entry */ 1186 NextEntry = NextEntry->Flink; 1187 1188 /* Skip this process if it's already been processed */ 1189 if (CsrProcess->Flags & CsrProcessSkipShutdown) continue; 1190 1191 /* Get the LUID of this process */ 1192 Status = CsrGetProcessLuid(CsrProcess->ProcessHandle, &ProcessLuid); 1193 1194 /* Check if we didn't get access to the LUID */ 1195 if (Status == STATUS_ACCESS_DENIED) 1196 { 1197 /* Check if we have any threads */ 1198 if (CsrProcess->ThreadCount) 1199 { 1200 /* Impersonate one of the threads and retry */ 1201 CsrThread = CONTAINING_RECORD(CsrProcess->ThreadList.Flink, 1202 CSR_THREAD, 1203 Link); 1204 if (CsrImpersonateClient(CsrThread)) 1205 { 1206 Status = CsrGetProcessLuid(NULL, &ProcessLuid); 1207 CsrRevertToSelf(); 1208 } 1209 else 1210 { 1211 Status = STATUS_BAD_IMPERSONATION_LEVEL; 1212 } 1213 } 1214 } 1215 1216 if (!NT_SUCCESS(Status)) 1217 { 1218 /* We didn't have access, so skip it */ 1219 CsrProcess->Flags |= CsrProcessSkipShutdown; 1220 continue; 1221 } 1222 1223 /* Check if this is the System LUID */ 1224 if (RtlEqualLuid(&ProcessLuid, &SystemLuid)) 1225 { 1226 /* Mark this process */ 1227 CsrProcess->ShutdownFlags |= CsrShutdownSystem; 1228 } 1229 else if (!RtlEqualLuid(&ProcessLuid, CallerLuid)) 1230 { 1231 /* Our LUID doesn't match with the caller's */ 1232 CsrProcess->ShutdownFlags |= CsrShutdownOther; 1233 } 1234 1235 /* Check if we're past the previous level */ 1236 if ((CsrProcess->ShutdownLevel > Level) || !ReturnCsrProcess) 1237 { 1238 /* Update the level */ 1239 Level = CsrProcess->ShutdownLevel; 1240 1241 /* Set the final process */ 1242 ReturnCsrProcess = CsrProcess; 1243 } 1244 } 1245 1246 /* Check if we found a process */ 1247 if (ReturnCsrProcess) 1248 { 1249 /* Skip this one next time */ 1250 ReturnCsrProcess->Flags |= CsrProcessSkipShutdown; 1251 } 1252 1253 return ReturnCsrProcess; 1254 } 1255 1256 /*++ 1257 * @name CsrShutdownProcesses 1258 * @implemented NT4 1259 * 1260 * The CsrShutdownProcesses routine shuts down every CSR Process possible 1261 * and calls each Server DLL's shutdown notification. 1262 * 1263 * @param CallerLuid 1264 * Pointer to the LUID of the CSR Process that is ordering the 1265 * shutdown. 1266 * 1267 * @param Flags 1268 * Flags to send to the shutdown notification routine. 1269 * 1270 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise. 1271 * 1272 * @remarks None. 1273 * 1274 *--*/ 1275 NTSTATUS 1276 NTAPI 1277 CsrShutdownProcesses(IN PLUID CallerLuid, 1278 IN ULONG Flags) 1279 { 1280 PLIST_ENTRY NextEntry; 1281 PCSR_PROCESS CsrProcess; 1282 NTSTATUS Status; 1283 BOOLEAN FirstTry; 1284 ULONG i; 1285 PCSR_SERVER_DLL ServerDll; 1286 ULONG Result = 0; 1287 1288 /* Acquire process lock */ 1289 CsrAcquireProcessLock(); 1290 1291 /* Add shutdown flag */ 1292 CsrRootProcess->ShutdownFlags |= CsrShutdownSystem; 1293 1294 /* Get the list pointers */ 1295 NextEntry = CsrRootProcess->ListLink.Flink; 1296 while (NextEntry != &CsrRootProcess->ListLink) 1297 { 1298 /* Get the Process */ 1299 CsrProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink); 1300 1301 /* Move to the next entry */ 1302 NextEntry = NextEntry->Flink; 1303 1304 /* Remove the skip flag, set shutdown flags to 0 */ 1305 CsrProcess->Flags &= ~CsrProcessSkipShutdown; 1306 CsrProcess->ShutdownFlags = 0; 1307 } 1308 1309 /* Set shutdown Priority */ 1310 CsrSetToShutdownPriority(); 1311 1312 /* Start looping */ 1313 while (TRUE) 1314 { 1315 /* Find the next process to shutdown */ 1316 CsrProcess = FindProcessForShutdown(CallerLuid); 1317 if (!CsrProcess) break; 1318 1319 /* Increase reference to process */ 1320 CsrLockedReferenceProcess(CsrProcess); 1321 1322 FirstTry = TRUE; 1323 while (TRUE) 1324 { 1325 /* Loop all the servers */ 1326 for (i = 0; i < CSR_SERVER_DLL_MAX; i++) 1327 { 1328 /* Get the current server */ 1329 ServerDll = CsrLoadedServerDll[i]; 1330 1331 /* Check if it's valid and if it has a Shutdown Process Callback */ 1332 if (ServerDll && ServerDll->ShutdownProcessCallback) 1333 { 1334 /* Release the lock, make the callback, and acquire it back */ 1335 CsrReleaseProcessLock(); 1336 Result = ServerDll->ShutdownProcessCallback(CsrProcess, 1337 Flags, 1338 FirstTry); 1339 CsrAcquireProcessLock(); 1340 1341 /* Check the result */ 1342 if (Result == CsrShutdownCsrProcess) 1343 { 1344 /* The callback unlocked the process */ 1345 break; 1346 } 1347 else if (Result == CsrShutdownCancelled) 1348 { 1349 #ifdef CSR_DBG 1350 /* Check if this was a forced shutdown */ 1351 if (Flags & EWX_FORCE) 1352 { 1353 DPRINT1("Process %x cancelled forced shutdown (Dll = %d)\n", 1354 CsrProcess->ClientId.UniqueProcess, i); 1355 DbgBreakPoint(); 1356 } 1357 #endif 1358 1359 /* Shutdown was cancelled, unlock and exit */ 1360 CsrReleaseProcessLock(); 1361 Status = STATUS_CANCELLED; 1362 goto Quickie; 1363 } 1364 } 1365 } 1366 1367 /* No matches during the first try, so loop again */ 1368 if (FirstTry && (Result == CsrShutdownNonCsrProcess)) 1369 { 1370 FirstTry = FALSE; 1371 continue; 1372 } 1373 1374 /* Second try, break out */ 1375 break; 1376 } 1377 1378 /* We've reached the final loop here, so dereference */ 1379 if (i == CSR_SERVER_DLL_MAX) 1380 CsrLockedDereferenceProcess(CsrProcess); 1381 } 1382 1383 /* Success path */ 1384 CsrReleaseProcessLock(); 1385 Status = STATUS_SUCCESS; 1386 1387 Quickie: 1388 /* Return to normal priority */ 1389 CsrSetToNormalPriority(); 1390 1391 return Status; 1392 } 1393 1394 /*++ 1395 * @name CsrUnlockProcess 1396 * @implemented NT4 1397 * 1398 * The CsrUnlockProcess undoes a previous CsrLockProcessByClientId operation. 1399 * 1400 * @param CsrProcess 1401 * Pointer to a previously locked CSR Process. 1402 * 1403 * @return STATUS_SUCCESS. 1404 * 1405 * @remarks This routine must be called with the Process Lock held. 1406 * 1407 *--*/ 1408 NTSTATUS 1409 NTAPI 1410 CsrUnlockProcess(IN PCSR_PROCESS CsrProcess) 1411 { 1412 /* Dereference the process */ 1413 CsrLockedDereferenceProcess(CsrProcess); 1414 1415 /* Release the lock and return */ 1416 CsrReleaseProcessLock(); 1417 return STATUS_SUCCESS; 1418 } 1419 1420 /* EOF */ 1421