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)
10 /* INCLUDES *******************************************************************/
19 /* GLOBALS ********************************************************************/
21 RTL_CRITICAL_SECTION CsrProcessLock
;
22 PCSR_PROCESS CsrRootProcess
= NULL
;
23 SECURITY_QUALITY_OF_SERVICE CsrSecurityQos
=
25 sizeof(SECURITY_QUALITY_OF_SERVICE
),
26 SecurityImpersonation
,
27 SECURITY_STATIC_TRACKING
,
30 ULONG CsrProcessSequenceCount
= 5;
31 extern ULONG CsrTotalPerProcessDataLength
;
34 /* PRIVATE FUNCTIONS **********************************************************/
37 * @name CsrSetToNormalPriority
39 * The CsrSetToNormalPriority routine sets the current NT Process'
40 * priority to the normal priority for CSR Processes.
46 * @remarks The "Normal" Priority corresponds to the Normal Foreground
47 * Priority (9) plus a boost of 4.
52 CsrSetToNormalPriority(VOID
)
54 KPRIORITY BasePriority
= (8 + 1) + 4;
56 /* Set the Priority */
57 NtSetInformationProcess(NtCurrentProcess(),
64 * @name CsrSetToShutdownPriority
66 * The CsrSetToShutdownPriority routine sets the current NT Process'
67 * priority to the boosted priority for CSR Processes doing shutdown.
68 * Additonally, it acquires the Shutdown Privilege required for shutdown.
74 * @remarks The "Shutdown" Priority corresponds to the Normal Foreground
75 * Priority (9) plus a boost of 6.
80 CsrSetToShutdownPriority(VOID
)
82 KPRIORITY SetBasePriority
= (8 + 1) + 6;
85 /* Get the shutdown privilege */
86 if (NT_SUCCESS(RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
,
91 /* Set the Priority */
92 NtSetInformationProcess(NtCurrentProcess(),
100 * @name CsrProcessRefcountZero
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.
106 * Pointer to the CSR Process that is to be deleted.
110 * @remarks Do not call this routine. It is reserved for the internal
111 * thread management routines when a CSR Process has lost all
114 * This routine is called with the Process Lock held.
119 CsrProcessRefcountZero(IN PCSR_PROCESS CsrProcess
)
121 ASSERT(ProcessStructureListLocked());
123 /* Remove the Process from the list */
124 CsrRemoveProcess(CsrProcess
);
126 /* Check if there's a session */
127 if (CsrProcess
->NtSession
)
129 /* Dereference the Session */
130 CsrDereferenceNtSession(CsrProcess
->NtSession
, 0);
133 /* Close the Client Port if there is one */
134 if (CsrProcess
->ClientPort
) NtClose(CsrProcess
->ClientPort
);
136 /* Close the process handle */
137 NtClose(CsrProcess
->ProcessHandle
);
139 /* Free the Proces Object */
140 CsrDeallocateProcess(CsrProcess
);
144 * @name CsrLockedDereferenceProcess
146 * The CsrLockedDereferenceProcess dereferences a CSR Process while the
147 * Process Lock is already being held.
150 * Pointer to the CSR Process to be dereferenced.
154 * @remarks This routine will return with the Process Lock held.
159 CsrLockedDereferenceProcess(PCSR_PROCESS CsrProcess
)
163 /* Decrease reference count */
164 LockCount
= --CsrProcess
->ReferenceCount
;
165 ASSERT(LockCount
>= 0);
168 /* Call the generic cleanup code */
169 DPRINT1("Should kill process: %p\n", CsrProcess
);
170 CsrAcquireProcessLock();
171 CsrProcessRefcountZero(CsrProcess
);
176 * @name CsrAllocateProcess
179 * The CsrAllocateProcess routine allocates a new CSR Process object.
181 * @return Pointer to the newly allocated CSR Process.
188 CsrAllocateProcess(VOID
)
190 PCSR_PROCESS CsrProcess
;
193 /* Calculate the amount of memory this should take */
194 TotalSize
= sizeof(CSR_PROCESS
) +
195 (CSR_SERVER_DLL_MAX
* sizeof(PVOID
)) +
196 CsrTotalPerProcessDataLength
;
198 /* Allocate a Process */
199 CsrProcess
= RtlAllocateHeap(CsrHeap
, HEAP_ZERO_MEMORY
, TotalSize
);
200 if (!CsrProcess
) return NULL
;
202 /* Handle the Sequence Number and protect against overflow */
203 CsrProcess
->SequenceNumber
= CsrProcessSequenceCount
++;
204 if (CsrProcessSequenceCount
< 5) CsrProcessSequenceCount
= 5;
206 /* Increase the reference count */
207 CsrLockedReferenceProcess(CsrProcess
);
209 /* Initialize the Thread List */
210 InitializeListHead(&CsrProcess
->ThreadList
);
212 /* Return the Process */
217 * @name CsrLockedReferenceProcess
219 * The CsrLockedReferenceProcess references a CSR Process while the
220 * Process Lock is already being held.
223 * Pointer to the CSR Process to be referenced.
227 * @remarks This routine will return with the Process Lock held.
232 CsrLockedReferenceProcess(IN PCSR_PROCESS CsrProcess
)
234 /* Increment the reference count */
235 ++CsrProcess
->ReferenceCount
;
239 * @name CsrInitializeProcessStructure
242 * The CsrInitializeProcessStructure routine sets up support for CSR Processes
243 * and CSR Threads by initializing our own CSR Root Process.
247 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
254 CsrInitializeProcessStructure(VOID
)
259 /* Initialize the Lock */
260 Status
= RtlInitializeCriticalSection(&CsrProcessLock
);
261 if (!NT_SUCCESS(Status
)) return Status
;
263 /* Set up the Root Process */
264 CsrRootProcess
= CsrAllocateProcess();
265 if (!CsrRootProcess
) return STATUS_NO_MEMORY
;
267 /* Set up the minimal information for it */
268 InitializeListHead(&CsrRootProcess
->ListLink
);
269 CsrRootProcess
->ProcessHandle
= (HANDLE
)-1;
270 CsrRootProcess
->ClientId
= NtCurrentTeb()->ClientId
;
272 /* Initialize the Thread Hash List */
273 for (i
= 0; i
< NUMBER_THREAD_HASH_BUCKETS
; i
++) InitializeListHead(&CsrThreadHashTable
[i
]);
275 /* Initialize the Wait Lock */
276 return RtlInitializeCriticalSection(&CsrWaitListsLock
);
280 * @name CsrDeallocateProcess
282 * The CsrDeallocateProcess frees the memory associated with a CSR Process.
285 * Pointer to the CSR Process to be freed.
289 * @remarks Do not call this routine. It is reserved for the internal
290 * thread management routines when a CSR Process has been cleanly
291 * dereferenced and killed.
296 CsrDeallocateProcess(IN PCSR_PROCESS CsrProcess
)
298 /* Free the process object from the heap */
299 RtlFreeHeap(CsrHeap
, 0, CsrProcess
);
303 * @name CsrRemoveProcess
305 * The CsrRemoveProcess function undoes a CsrInsertProcess operation and
306 * removes the CSR Process from the Process List and notifies Server DLLs
310 * Pointer to the CSR Process to remove.
319 CsrRemoveProcess(IN PCSR_PROCESS CsrProcess
)
321 PCSR_SERVER_DLL ServerDll
;
323 ASSERT(ProcessStructureListLocked());
325 /* Remove us from the Process List */
326 RemoveEntryList(&CsrProcess
->ListLink
);
328 /* Release the lock */
329 CsrReleaseProcessLock();
331 /* Loop every Server DLL */
332 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
334 /* Get the Server DLL */
335 ServerDll
= CsrLoadedServerDll
[i
];
337 /* Check if it's valid and if it has a Disconnect Callback */
338 if (ServerDll
&& ServerDll
->DisconnectCallback
)
341 ServerDll
->DisconnectCallback(CsrProcess
);
347 * @name CsrInsertProcess
349 * The CsrInsertProcess routine inserts a CSR Process into the Process List
350 * and notifies Server DLLs of the creation of a new CSR Process.
352 * @param ParentProcess
353 * Optional pointer to the Parent Process creating this CSR Process.
356 * Pointer to the CSR Process which is to be inserted.
365 CsrInsertProcess(IN PCSR_PROCESS ParentProcess OPTIONAL
,
366 IN PCSR_PROCESS CsrProcess
)
368 PCSR_SERVER_DLL ServerDll
;
370 ASSERT(ProcessStructureListLocked());
372 /* Insert it into the Root List */
373 InsertTailList(&CsrRootProcess
->ListLink
, &CsrProcess
->ListLink
);
375 /* Notify the Server DLLs */
376 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
378 /* Get the current Server DLL */
379 ServerDll
= CsrLoadedServerDll
[i
];
381 /* Make sure it's valid and that it has callback */
382 if (ServerDll
&& ServerDll
->NewProcessCallback
)
384 ServerDll
->NewProcessCallback(ParentProcess
, CsrProcess
);
390 /* PUBLIC FUNCTIONS ***********************************************************/
393 * @name CsrCreateProcess
396 * The CsrCreateProcess routine creates a CSR Process object for an NT Process.
399 * Handle to an existing NT Process to which to associate this
403 * Handle to an existing NT Thread to which to create its
404 * corresponding CSR Thread for this CSR Process.
407 * Pointer to the Client ID structure of the NT Process to associate
408 * with this CSR Process.
414 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
421 CsrCreateProcess(IN HANDLE hProcess
,
423 IN PCLIENT_ID ClientId
,
424 IN PCSR_NT_SESSION NtSession
,
426 IN PCLIENT_ID DebugCid
)
428 PCSR_THREAD CurrentThread
= CsrGetClientThread();
429 CLIENT_ID CurrentCid
;
430 PCSR_PROCESS CurrentProcess
;
431 PCSR_SERVER_DLL ServerDll
;
434 PCSR_PROCESS CsrProcess
;
436 PCSR_THREAD CsrThread
;
437 KERNEL_USER_TIMES KernelTimes
;
439 /* Get the current CID and lock Processes */
440 CurrentCid
= CurrentThread
->ClientId
;
441 CsrAcquireProcessLock();
443 /* Get the current CSR Thread */
444 CurrentThread
= CsrLocateThreadByClientId(&CurrentProcess
, &CurrentCid
);
447 /* We've failed to locate the thread */
448 CsrReleaseProcessLock();
449 return STATUS_THREAD_IS_TERMINATING
;
452 /* Allocate a new Process Object */
453 CsrProcess
= CsrAllocateProcess();
456 /* Couldn't allocate Process */
457 CsrReleaseProcessLock();
458 return STATUS_NO_MEMORY
;
461 /* Inherit the Process Data */
462 CurrentProcess
= CurrentThread
->Process
;
463 ProcessData
= &CsrProcess
->ServerData
[CSR_SERVER_DLL_MAX
];
464 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
466 /* Get the current Server */
467 ServerDll
= CsrLoadedServerDll
[i
];
469 /* Check if the DLL is Loaded and has Per Process Data */
470 if (ServerDll
&& ServerDll
->SizeOfProcessData
)
472 /* Set the pointer */
473 CsrProcess
->ServerData
[i
] = ProcessData
;
476 RtlMoveMemory(ProcessData
,
477 CurrentProcess
->ServerData
[i
],
478 ServerDll
->SizeOfProcessData
);
480 /* Update next data pointer */
481 ProcessData
= (PVOID
)((ULONG_PTR
)ProcessData
+
482 ServerDll
->SizeOfProcessData
);
486 /* No data for this Server */
487 CsrProcess
->ServerData
[i
] = NULL
;
491 /* Set the Exception port for us */
492 Status
= NtSetInformationProcess(hProcess
,
493 ProcessExceptionPort
,
496 if (!NT_SUCCESS(Status
))
499 CsrDeallocateProcess(CsrProcess
);
500 CsrReleaseProcessLock();
501 return STATUS_NO_MEMORY
;
504 /* Check if CreateProcess got CREATE_NEW_PROCESS_GROUP */
505 if (Flags
& CsrProcessCreateNewGroup
)
508 * We create the process group leader of a new process group, therefore
509 * its process group ID and sequence number are its own ones.
511 CsrProcess
->ProcessGroupId
= HandleToUlong(ClientId
->UniqueProcess
);
512 CsrProcess
->ProcessGroupSequence
= CsrProcess
->SequenceNumber
;
516 /* Inherit the process group ID and sequence number from the current process */
517 CsrProcess
->ProcessGroupId
= CurrentProcess
->ProcessGroupId
;
518 CsrProcess
->ProcessGroupSequence
= CurrentProcess
->ProcessGroupSequence
;
521 /* Check if this is a console process */
522 if (Flags
& CsrProcessIsConsoleApp
) CsrProcess
->Flags
|= CsrProcessIsConsoleApp
;
524 /* Mask out non-debug flags */
525 Flags
&= ~(CsrProcessIsConsoleApp
| CsrProcessCreateNewGroup
| CsrProcessPriorityFlags
);
527 /* Check if every process will be debugged */
528 if (!(Flags
) && (CurrentProcess
->DebugFlags
& CsrDebugProcessChildren
))
530 /* Pass it on to the current process */
531 CsrProcess
->DebugFlags
= CsrDebugProcessChildren
;
532 CsrProcess
->DebugCid
= CurrentProcess
->DebugCid
;
535 /* Check if Debugging was used on this process */
536 if ((Flags
& (CsrDebugOnlyThisProcess
| CsrDebugProcessChildren
)) && (DebugCid
))
538 /* Save the debug flag used */
539 CsrProcess
->DebugFlags
= Flags
;
542 CsrProcess
->DebugCid
= *DebugCid
;
545 /* Check if Debugging is enabled */
546 if (CsrProcess
->DebugFlags
)
548 /* Set the Debug Port for us */
549 Status
= NtSetInformationProcess(hProcess
,
553 ASSERT(NT_SUCCESS(Status
));
554 if (!NT_SUCCESS(Status
))
557 CsrDeallocateProcess(CsrProcess
);
558 CsrReleaseProcessLock();
559 return STATUS_NO_MEMORY
;
563 /* Get the Thread Create Time */
564 Status
= NtQueryInformationThread(hThread
,
569 if (!NT_SUCCESS(Status
))
572 CsrDeallocateProcess(CsrProcess
);
573 CsrReleaseProcessLock();
574 return STATUS_NO_MEMORY
;
577 /* Allocate a CSR Thread Structure */
578 CsrThread
= CsrAllocateThread(CsrProcess
);
582 CsrDeallocateProcess(CsrProcess
);
583 CsrReleaseProcessLock();
584 return STATUS_NO_MEMORY
;
587 /* Save the data we have */
588 CsrThread
->CreateTime
= KernelTimes
.CreateTime
;
589 CsrThread
->ClientId
= *ClientId
;
590 CsrThread
->ThreadHandle
= hThread
;
591 ProtectHandle(hThread
);
592 CsrThread
->Flags
= 0;
594 /* Insert the Thread into the Process */
595 Status
= CsrInsertThread(CsrProcess
, CsrThread
);
596 if (!NT_SUCCESS(Status
))
599 CsrDeallocateProcess(CsrProcess
);
600 CsrDeallocateThread(CsrThread
);
601 CsrReleaseProcessLock();
605 /* Reference the session */
606 CsrReferenceNtSession(NtSession
);
607 CsrProcess
->NtSession
= NtSession
;
609 /* Setup Process Data */
610 CsrProcess
->ClientId
= *ClientId
;
611 CsrProcess
->ProcessHandle
= hProcess
;
612 CsrProcess
->ShutdownLevel
= 0x280;
614 /* Set the Priority to Background */
615 CsrSetBackgroundPriority(CsrProcess
);
617 /* Insert the Process */
618 CsrInsertProcess(CurrentProcess
, CsrProcess
);
620 /* Release lock and return */
621 CsrReleaseProcessLock();
626 * @name CsrDebugProcess
629 * The CsrDebugProcess routine is deprecated in NT 5.1 and higher. It is
630 * exported only for compatibility with older CSR Server DLLs.
637 * @remarks Deprecated.
642 CsrDebugProcess(IN PCSR_PROCESS CsrProcess
)
644 /* CSR does not handle debugging anymore */
645 DPRINT("CSRSRV: %s(0x%p) called\n", __FUNCTION__
, CsrProcess
);
646 return STATUS_UNSUCCESSFUL
;
650 * @name CsrDebugProcessStop
653 * The CsrDebugProcessStop routine is deprecated in NT 5.1 and higher. It is
654 * exported only for compatibility with older CSR Server DLLs.
661 * @remarks Deprecated.
666 CsrDebugProcessStop(IN PCSR_PROCESS CsrProcess
)
668 /* CSR does not handle debugging anymore */
669 DPRINT("CSRSRV: %s(0x%p) called\n", __FUNCTION__
, CsrProcess
);
670 return STATUS_UNSUCCESSFUL
;
674 * @name CsrDereferenceProcess
677 * The CsrDereferenceProcess routine removes a reference from a CSR Process.
680 * Pointer to the CSR Process to dereference.
684 * @remarks If the reference count has reached zero (ie: the CSR Process has
685 * no more active references), it will be deleted.
690 CsrDereferenceProcess(IN PCSR_PROCESS CsrProcess
)
694 /* Acquire process lock */
695 CsrAcquireProcessLock();
697 /* Decrease reference count */
698 LockCount
= --CsrProcess
->ReferenceCount
;
699 ASSERT(LockCount
>= 0);
702 /* Call the generic cleanup code */
703 CsrProcessRefcountZero(CsrProcess
);
707 /* Just release the lock */
708 CsrReleaseProcessLock();
713 * @name CsrDestroyProcess
716 * The CsrDestroyProcess routine destroys the CSR Process corresponding to
720 * Pointer to the Client ID Structure corresponding to the CSR
721 * Process which is about to be destroyed.
726 * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING
727 * if the CSR Process is already terminating.
734 CsrDestroyProcess(IN PCLIENT_ID Cid
,
735 IN NTSTATUS ExitStatus
)
737 PCSR_THREAD CsrThread
;
738 PCSR_PROCESS CsrProcess
;
739 CLIENT_ID ClientId
= *Cid
;
740 PLIST_ENTRY NextEntry
;
743 CsrAcquireProcessLock();
745 /* Find the thread */
746 CsrThread
= CsrLocateThreadByClientId(&CsrProcess
, &ClientId
);
748 /* Make sure we got one back, and that it's not already gone */
749 if (!(CsrThread
) || (CsrProcess
->Flags
& CsrProcessTerminating
))
751 /* Release the lock and return failure */
752 CsrReleaseProcessLock();
753 return STATUS_THREAD_IS_TERMINATING
;
756 /* Set the terminated flag */
757 CsrProcess
->Flags
|= CsrProcessTerminating
;
759 /* Get the List Pointers */
760 NextEntry
= CsrProcess
->ThreadList
.Flink
;
761 while (NextEntry
!= &CsrProcess
->ThreadList
)
763 /* Get the current thread entry */
764 CsrThread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
766 /* Move to the next entry */
767 NextEntry
= NextEntry
->Flink
;
769 /* Make sure the thread isn't already dead */
770 if (CsrThread
->Flags
& CsrThreadTerminated
)
772 /* Go the the next thread */
776 /* Set the Terminated flag */
777 CsrThread
->Flags
|= CsrThreadTerminated
;
779 /* Acquire the Wait Lock */
780 CsrAcquireWaitLock();
782 /* Do we have an active wait block? */
783 if (CsrThread
->WaitBlock
)
785 /* Notify waiters of termination */
786 CsrNotifyWaitBlock(CsrThread
->WaitBlock
,
790 CsrProcessTerminating
,
794 /* Release the Wait Lock */
795 CsrReleaseWaitLock();
797 /* Dereference the thread */
798 CsrLockedDereferenceThread(CsrThread
);
801 /* Release the Process Lock and return success */
802 CsrReleaseProcessLock();
803 return STATUS_SUCCESS
;
807 * @name CsrGetProcessLuid
810 * The CsrGetProcessLuid routine gets the LUID of the given process.
813 * Optional handle to the process whose LUID should be returned.
816 * Pointer to a LUID Pointer which will receive the CSR Process' LUID.
818 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
820 * @remarks If hProcess is not supplied, then the current thread's token will
821 * be used. If that too is missing, then the current process' token
827 CsrGetProcessLuid(IN HANDLE hProcess OPTIONAL
,
830 HANDLE hToken
= NULL
;
833 PTOKEN_STATISTICS TokenStats
;
835 /* Check if we have a handle to a CSR Process */
838 /* We don't, so try opening the Thread's Token */
839 Status
= NtOpenThreadToken(NtCurrentThread(),
844 /* Check for success */
845 if (!NT_SUCCESS(Status
))
847 /* If we got some other failure, then return and quit */
848 if (Status
!= STATUS_NO_TOKEN
) return Status
;
850 /* We don't have a Thread Token, use a Process Token */
851 hProcess
= NtCurrentProcess();
856 /* Check if we have a token by now */
859 /* No token yet, so open the Process Token */
860 Status
= NtOpenProcessToken(hProcess
,
863 if (!NT_SUCCESS(Status
))
865 /* Still no token, return the error */
870 /* Now get the size we'll need for the Token Information */
871 Status
= NtQueryInformationToken(hToken
,
877 /* Allocate memory for the Token Info */
878 if (!(TokenStats
= RtlAllocateHeap(CsrHeap
, 0, Length
)))
880 /* Fail and close the token */
882 return STATUS_NO_MEMORY
;
885 /* Now query the information */
886 Status
= NtQueryInformationToken(hToken
,
892 /* Close the handle */
895 /* Check for success */
896 if (NT_SUCCESS(Status
))
898 /* Return the LUID */
899 *Luid
= TokenStats
->AuthenticationId
;
902 /* Free the query information */
903 RtlFreeHeap(CsrHeap
, 0, TokenStats
);
905 /* Return the Status */
910 * @name CsrImpersonateClient
913 * The CsrImpersonateClient will impersonate the given CSR Thread.
916 * Pointer to the CSR Thread to impersonate.
918 * @return TRUE if impersonation succeeded, FALSE otherwise.
920 * @remarks Impersonation can be recursive.
925 CsrImpersonateClient(IN PCSR_THREAD CsrThread
)
928 PCSR_THREAD CurrentThread
= CsrGetClientThread();
930 /* Use the current thread if none given */
931 if (!CsrThread
) CsrThread
= CurrentThread
;
933 /* Still no thread, something is wrong */
941 Status
= NtImpersonateThread(NtCurrentThread(),
942 CsrThread
->ThreadHandle
,
945 if (!NT_SUCCESS(Status
))
948 DPRINT1("CSRSS: Can't impersonate client thread - Status = %lx\n", Status
);
949 // if (Status != STATUS_BAD_IMPERSONATION_LEVEL) DbgBreakPoint();
953 /* Increase the impersonation count for the current thread */
954 if (CurrentThread
) ++CurrentThread
->ImpersonationCount
;
961 * @name CsrLockProcessByClientId
964 * The CsrLockProcessByClientId routine locks the CSR Process corresponding
965 * to the given Process ID and optionally returns it.
968 * Process ID corresponding to the CSR Process which will be locked.
971 * Optional pointer to a CSR Process pointer which will hold the
972 * CSR Process corresponding to the given Process ID.
974 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
976 * @remarks Locking a CSR Process is defined as acquiring an extra
977 * reference to it and returning with the Process Lock held.
982 CsrLockProcessByClientId(IN HANDLE Pid
,
983 OUT PCSR_PROCESS
*CsrProcess
)
985 PLIST_ENTRY NextEntry
;
986 PCSR_PROCESS CurrentProcess
= NULL
;
987 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
989 /* Acquire the lock */
990 CsrAcquireProcessLock();
993 ASSERT(CsrProcess
!= NULL
);
996 /* Setup the List Pointers */
997 NextEntry
= &CsrRootProcess
->ListLink
;
1000 /* Get the Process */
1001 CurrentProcess
= CONTAINING_RECORD(NextEntry
, CSR_PROCESS
, ListLink
);
1003 /* Check for PID Match */
1004 if (CurrentProcess
->ClientId
.UniqueProcess
== Pid
)
1006 Status
= STATUS_SUCCESS
;
1010 /* Move to the next entry */
1011 NextEntry
= NextEntry
->Flink
;
1012 } while (NextEntry
!= &CsrRootProcess
->ListLink
);
1014 /* Check if we didn't find it in the list */
1015 if (!NT_SUCCESS(Status
))
1017 /* Nothing found, release the lock */
1018 CsrReleaseProcessLock();
1022 /* Lock the found process and return it */
1023 CsrLockedReferenceProcess(CurrentProcess
);
1024 *CsrProcess
= CurrentProcess
;
1027 /* Return the result */
1032 * @name CsrRevertToSelf
1035 * The CsrRevertToSelf routine will attempt to remove an active impersonation.
1039 * @return TRUE if the reversion was succesful, FALSE otherwise.
1041 * @remarks Impersonation can be recursive; as such, the impersonation token
1042 * will only be deleted once the CSR Thread's impersonaton count
1048 CsrRevertToSelf(VOID
)
1051 PCSR_THREAD CurrentThread
= CsrGetClientThread();
1052 HANDLE ImpersonationToken
= NULL
;
1054 /* Check if we have a Current Thread */
1057 /* Make sure impersonation is on */
1058 if (!CurrentThread
->ImpersonationCount
)
1060 DPRINT1("CSRSS: CsrRevertToSelf called while not impersonating\n");
1064 else if ((--CurrentThread
->ImpersonationCount
) > 0)
1066 /* Success; impersonation count decreased but still not zero */
1071 /* Impersonation has been totally removed, revert to ourselves */
1072 Status
= NtSetInformationThread(NtCurrentThread(),
1073 ThreadImpersonationToken
,
1074 &ImpersonationToken
,
1077 /* Return TRUE or FALSE */
1078 return NT_SUCCESS(Status
);
1082 * @name CsrSetBackgroundPriority
1085 * The CsrSetBackgroundPriority routine sets the priority for the given CSR
1086 * Process as a Background priority.
1089 * Pointer to the CSR Process whose priority will be modified.
1098 CsrSetBackgroundPriority(IN PCSR_PROCESS CsrProcess
)
1100 PROCESS_PRIORITY_CLASS PriorityClass
;
1102 /* Set the Foreground bit off */
1103 PriorityClass
.Foreground
= FALSE
;
1105 /* Set the new Priority */
1106 NtSetInformationProcess(CsrProcess
->ProcessHandle
,
1107 ProcessPriorityClass
,
1109 sizeof(PriorityClass
));
1113 * @name CsrSetForegroundPriority
1116 * The CsrSetForegroundPriority routine sets the priority for the given CSR
1117 * Process as a Foreground priority.
1120 * Pointer to the CSR Process whose priority will be modified.
1129 CsrSetForegroundPriority(IN PCSR_PROCESS CsrProcess
)
1131 PROCESS_PRIORITY_CLASS PriorityClass
;
1133 /* Set the Foreground bit on */
1134 PriorityClass
.Foreground
= TRUE
;
1136 /* Set the new Priority */
1137 NtSetInformationProcess(CsrProcess
->ProcessHandle
,
1138 ProcessPriorityClass
,
1140 sizeof(PriorityClass
));
1144 * @name FindProcessForShutdown
1146 * The FindProcessForShutdown routine returns a CSR Process which is ready
1147 * to be shutdown, and sets the appropriate shutdown flags for it.
1150 * Pointer to the LUID of the CSR Process calling this routine.
1152 * @return Pointer to a CSR Process which is ready to be shutdown.
1159 FindProcessForShutdown(IN PLUID CallerLuid
)
1161 PCSR_PROCESS CsrProcess
, ReturnCsrProcess
= NULL
;
1162 PCSR_THREAD CsrThread
;
1166 LUID SystemLuid
= SYSTEM_LUID
;
1167 PLIST_ENTRY NextEntry
;
1169 /* Set the List Pointers */
1170 NextEntry
= CsrRootProcess
->ListLink
.Flink
;
1171 while (NextEntry
!= &CsrRootProcess
->ListLink
)
1173 /* Get the process */
1174 CsrProcess
= CONTAINING_RECORD(NextEntry
, CSR_PROCESS
, ListLink
);
1176 /* Move to the next entry */
1177 NextEntry
= NextEntry
->Flink
;
1179 /* Skip this process if it's already been processed */
1180 if (CsrProcess
->Flags
& CsrProcessSkipShutdown
) continue;
1182 /* Get the LUID of this process */
1183 Status
= CsrGetProcessLuid(CsrProcess
->ProcessHandle
, &ProcessLuid
);
1185 /* Check if we didn't get access to the LUID */
1186 if (Status
== STATUS_ACCESS_DENIED
)
1188 /* Check if we have any threads */
1189 if (CsrProcess
->ThreadCount
)
1191 /* Impersonate one of the threads and retry */
1192 CsrThread
= CONTAINING_RECORD(CsrProcess
->ThreadList
.Flink
,
1195 if (CsrImpersonateClient(CsrThread
))
1197 Status
= CsrGetProcessLuid(NULL
, &ProcessLuid
);
1202 Status
= STATUS_BAD_IMPERSONATION_LEVEL
;
1207 if (!NT_SUCCESS(Status
))
1209 /* We didn't have access, so skip it */
1210 CsrProcess
->Flags
|= CsrProcessSkipShutdown
;
1214 /* Check if this is the System LUID */
1215 if (RtlEqualLuid(&ProcessLuid
, &SystemLuid
))
1217 /* Mark this process */
1218 CsrProcess
->ShutdownFlags
|= CsrShutdownSystem
;
1220 else if (!RtlEqualLuid(&ProcessLuid
, CallerLuid
))
1222 /* Our LUID doesn't match with the caller's */
1223 CsrProcess
->ShutdownFlags
|= CsrShutdownOther
;
1226 /* Check if we're past the previous level */
1227 if ((CsrProcess
->ShutdownLevel
> Level
) || !ReturnCsrProcess
)
1229 /* Update the level */
1230 Level
= CsrProcess
->ShutdownLevel
;
1232 /* Set the final process */
1233 ReturnCsrProcess
= CsrProcess
;
1237 /* Check if we found a process */
1238 if (ReturnCsrProcess
)
1240 /* Skip this one next time */
1241 ReturnCsrProcess
->Flags
|= CsrProcessSkipShutdown
;
1244 return ReturnCsrProcess
;
1248 * @name CsrShutdownProcesses
1251 * The CsrShutdownProcesses routine shuts down every CSR Process possible
1252 * and calls each Server DLL's shutdown notification.
1255 * Pointer to the LUID of the CSR Process that is ordering the
1259 * Flags to send to the shutdown notification routine.
1261 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
1268 CsrShutdownProcesses(IN PLUID CallerLuid
,
1271 PLIST_ENTRY NextEntry
;
1272 PCSR_PROCESS CsrProcess
;
1276 PCSR_SERVER_DLL ServerDll
;
1279 /* Acquire process lock */
1280 CsrAcquireProcessLock();
1282 /* Add shutdown flag */
1283 CsrRootProcess
->ShutdownFlags
|= CsrShutdownSystem
;
1285 /* Get the list pointers */
1286 NextEntry
= CsrRootProcess
->ListLink
.Flink
;
1287 while (NextEntry
!= &CsrRootProcess
->ListLink
)
1289 /* Get the Process */
1290 CsrProcess
= CONTAINING_RECORD(NextEntry
, CSR_PROCESS
, ListLink
);
1292 /* Move to the next entry */
1293 NextEntry
= NextEntry
->Flink
;
1295 /* Remove the skip flag, set shutdown flags to 0 */
1296 CsrProcess
->Flags
&= ~CsrProcessSkipShutdown
;
1297 CsrProcess
->ShutdownFlags
= 0;
1300 /* Set shutdown Priority */
1301 CsrSetToShutdownPriority();
1306 /* Find the next process to shutdown */
1307 CsrProcess
= FindProcessForShutdown(CallerLuid
);
1308 if (!CsrProcess
) break;
1310 /* Increase reference to process */
1311 CsrLockedReferenceProcess(CsrProcess
);
1316 /* Loop all the servers */
1317 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
1319 /* Get the current server */
1320 ServerDll
= CsrLoadedServerDll
[i
];
1322 /* Check if it's valid and if it has a Shutdown Process Callback */
1323 if (ServerDll
&& ServerDll
->ShutdownProcessCallback
)
1325 /* Release the lock, make the callback, and acquire it back */
1326 CsrReleaseProcessLock();
1327 Result
= ServerDll
->ShutdownProcessCallback(CsrProcess
,
1330 CsrAcquireProcessLock();
1332 /* Check the result */
1333 if (Result
== CsrShutdownCsrProcess
)
1335 /* The callback unlocked the process */
1338 else if (Result
== CsrShutdownCancelled
)
1340 /* Check if this was a forced shutdown */
1341 if (Flags
& EWX_FORCE
)
1343 DPRINT1("Process %x cancelled forced shutdown (Dll = %d)\n",
1344 CsrProcess
->ClientId
.UniqueProcess
, i
);
1348 /* Shutdown was cancelled, unlock and exit */
1349 CsrReleaseProcessLock();
1350 Status
= STATUS_CANCELLED
;
1356 /* No matches during the first try, so loop again */
1357 if (FirstTry
&& (Result
== CsrShutdownNonCsrProcess
))
1363 /* Second try, break out */
1367 /* We've reached the final loop here, so dereference */
1368 if (i
== CSR_SERVER_DLL_MAX
) CsrLockedDereferenceProcess(CsrProcess
);
1372 CsrReleaseProcessLock();
1373 Status
= STATUS_SUCCESS
;
1376 /* Return to normal priority */
1377 CsrSetToNormalPriority();
1383 * @name CsrUnlockProcess
1386 * The CsrUnlockProcess undoes a previous CsrLockProcessByClientId operation.
1389 * Pointer to a previously locked CSR Process.
1391 * @return STATUS_SUCCESS.
1393 * @remarks This routine must be called with the Process Lock held.
1398 CsrUnlockProcess(IN PCSR_PROCESS CsrProcess
)
1400 /* Dereference the process */
1401 CsrLockedDereferenceProcess(CsrProcess
);
1403 /* Release the lock and return */
1404 CsrReleaseProcessLock();
1405 return STATUS_SUCCESS
;