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 FindProcessForShutdown
102 * The FindProcessForShutdown routine returns a CSR Process which is ready
103 * to be shutdown, and sets the appropriate shutdown flags for it.
106 * Pointer to the LUID of the CSR Process calling this routine.
108 * @return Pointer to a CSR Process which is ready to be shutdown.
115 FindProcessForShutdown(IN PLUID CallerLuid
)
117 PCSR_PROCESS CsrProcess
, ReturnCsrProcess
= NULL
;
118 // PCSR_THREAD CsrThread;
122 LUID SystemLuid
= SYSTEM_LUID
;
123 // BOOLEAN IsSystemLuid = FALSE, IsOurLuid = FALSE;
124 PLIST_ENTRY NextEntry
;
126 /* Set the List Pointers */
127 NextEntry
= CsrRootProcess
->ListLink
.Flink
;
128 while (NextEntry
!= &CsrRootProcess
->ListLink
)
130 /* Get the process */
131 CsrProcess
= CONTAINING_RECORD(NextEntry
, CSR_PROCESS
, ListLink
);
133 /* Move to the next entry */
134 NextEntry
= NextEntry
->Flink
;
136 /* Skip this process if it's already been processed */
137 if (CsrProcess
->Flags
& CsrProcessSkipShutdown
) continue;
139 /* Get the LUID of this Process */
140 Status
= CsrGetProcessLuid(CsrProcess
->ProcessHandle
, &ProcessLuid
);
142 /* Check if we didn't get access to the LUID */
143 if (Status
== STATUS_ACCESS_DENIED
)
145 /* FIXME: Check if we have any threads */
147 /\* Check if we have any threads *\/
148 if (CsrProcess->ThreadCount)
150 /\* Impersonate one of the threads and retry *\/
151 CsrThread = CONTAINING_RECORD(CsrProcess->ThreadList.Flink,
154 CsrImpersonateClient(CsrThread);
155 Status = CsrGetProcessLuid(NULL, &ProcessLuid);
161 if (!NT_SUCCESS(Status
))
163 /* We didn't have access, so skip it */
164 CsrProcess
->Flags
|= CsrProcessSkipShutdown
;
168 /* Check if this is the System LUID */
169 if ((/*IsSystemLuid =*/ RtlEqualLuid(&ProcessLuid
, &SystemLuid
)))
171 /* Mark this process */
172 CsrProcess
->ShutdownFlags
|= CsrShutdownSystem
;
174 else if (!(/*IsOurLuid =*/ RtlEqualLuid(&ProcessLuid
, CallerLuid
)))
176 /* Our LUID doesn't match with the caller's */
177 CsrProcess
->ShutdownFlags
|= CsrShutdownOther
;
180 /* Check if we're past the previous level */
181 // FIXME: if ((CsrProcess->ShutdownLevel > Level) || !(ReturnCsrProcess))
182 if (CsrProcess
->ShutdownLevel
> Level
/* || !ReturnCsrProcess */)
184 /* Update the level */
185 Level
= CsrProcess
->ShutdownLevel
;
187 /* Set the final process */
188 ReturnCsrProcess
= CsrProcess
;
192 /* Check if we found a process */
193 if (ReturnCsrProcess
)
195 /* Skip this one next time */
196 ReturnCsrProcess
->Flags
|= CsrProcessSkipShutdown
;
199 return ReturnCsrProcess
;
203 * @name CsrProcessRefcountZero
205 * The CsrProcessRefcountZero routine is executed when a CSR Process has lost
206 * all its active references. It removes and de-allocates the CSR Process.
209 * Pointer to the CSR Process that is to be deleted.
213 * @remarks Do not call this routine. It is reserved for the internal
214 * thread management routines when a CSR Process has lost all
217 * This routine is called with the Process Lock held.
222 CsrProcessRefcountZero(IN PCSR_PROCESS CsrProcess
)
224 ASSERT(ProcessStructureListLocked());
226 /* Remove the Process from the list */
227 CsrRemoveProcess(CsrProcess
);
229 /* Check if there's a session */
230 if (CsrProcess
->NtSession
)
232 /* Dereference the Session */
233 CsrDereferenceNtSession(CsrProcess
->NtSession
, 0);
236 /* Close the Client Port if there is one */
237 if (CsrProcess
->ClientPort
) NtClose(CsrProcess
->ClientPort
);
239 /* Close the process handle */
240 NtClose(CsrProcess
->ProcessHandle
);
242 /* Free the Proces Object */
243 CsrDeallocateProcess(CsrProcess
);
247 * @name CsrLockedDereferenceProcess
249 * The CsrLockedDereferenceProcess dereferences a CSR Process while the
250 * Process Lock is already being held.
253 * Pointer to the CSR Process to be dereferenced.
257 * @remarks This routine will return with the Process Lock held.
262 CsrLockedDereferenceProcess(PCSR_PROCESS CsrProcess
)
266 /* Decrease reference count */
267 LockCount
= --CsrProcess
->ReferenceCount
;
268 ASSERT(LockCount
>= 0);
271 /* Call the generic cleanup code */
272 DPRINT1("Should kill process: %p\n", CsrProcess
);
273 CsrAcquireProcessLock();
274 CsrProcessRefcountZero(CsrProcess
);
279 * @name CsrAllocateProcess
282 * The CsrAllocateProcess routine allocates a new CSR Process object.
284 * @return Pointer to the newly allocated CSR Process.
291 CsrAllocateProcess(VOID
)
293 PCSR_PROCESS CsrProcess
;
296 /* Calculate the amount of memory this should take */
297 TotalSize
= sizeof(CSR_PROCESS
) +
298 (CSR_SERVER_DLL_MAX
* sizeof(PVOID
)) +
299 CsrTotalPerProcessDataLength
;
301 /* Allocate a Process */
302 CsrProcess
= RtlAllocateHeap(CsrHeap
, HEAP_ZERO_MEMORY
, TotalSize
);
303 if (!CsrProcess
) return NULL
;
305 /* Handle the Sequence Number and protect against overflow */
306 CsrProcess
->SequenceNumber
= CsrProcessSequenceCount
++;
307 if (CsrProcessSequenceCount
< 5) CsrProcessSequenceCount
= 5;
309 /* Increase the reference count */
310 CsrLockedReferenceProcess(CsrProcess
);
312 /* Initialize the Thread List */
313 InitializeListHead(&CsrProcess
->ThreadList
);
315 /* Return the Process */
320 * @name CsrLockedReferenceProcess
322 * The CsrLockedReferenceProcess references a CSR Process while the
323 * Process Lock is already being held.
326 * Pointer to the CSR Process to be referenced.
330 * @remarks This routine will return with the Process Lock held.
335 CsrLockedReferenceProcess(IN PCSR_PROCESS CsrProcess
)
337 /* Increment the reference count */
338 ++CsrProcess
->ReferenceCount
;
342 * @name CsrInitializeProcessStructure
345 * The CsrInitializeProcessStructure routine sets up support for CSR Processes
346 * and CSR Threads by initializing our own CSR Root Process.
350 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
357 CsrInitializeProcessStructure(VOID
)
362 /* Initialize the Lock */
363 Status
= RtlInitializeCriticalSection(&CsrProcessLock
);
364 if (!NT_SUCCESS(Status
)) return Status
;
366 /* Set up the Root Process */
367 CsrRootProcess
= CsrAllocateProcess();
368 if (!CsrRootProcess
) return STATUS_NO_MEMORY
;
370 /* Set up the minimal information for it */
371 InitializeListHead(&CsrRootProcess
->ListLink
);
372 CsrRootProcess
->ProcessHandle
= (HANDLE
)-1;
373 CsrRootProcess
->ClientId
= NtCurrentTeb()->ClientId
;
375 /* Initialize the Thread Hash List */
376 for (i
= 0; i
< NUMBER_THREAD_HASH_BUCKETS
; i
++) InitializeListHead(&CsrThreadHashTable
[i
]);
378 /* Initialize the Wait Lock */
379 return RtlInitializeCriticalSection(&CsrWaitListsLock
);
383 * @name CsrDeallocateProcess
385 * The CsrDeallocateProcess frees the memory associated with a CSR Process.
388 * Pointer to the CSR Process to be freed.
392 * @remarks Do not call this routine. It is reserved for the internal
393 * thread management routines when a CSR Process has been cleanly
394 * dereferenced and killed.
399 CsrDeallocateProcess(IN PCSR_PROCESS CsrProcess
)
401 /* Free the process object from the heap */
402 RtlFreeHeap(CsrHeap
, 0, CsrProcess
);
406 * @name CsrRemoveProcess
408 * The CsrRemoveProcess function undoes a CsrInsertProcess operation and
409 * removes the CSR Process from the Process List and notifies Server DLLs
413 * Pointer to the CSR Process to remove.
422 CsrRemoveProcess(IN PCSR_PROCESS CsrProcess
)
424 PCSR_SERVER_DLL ServerDll
;
426 ASSERT(ProcessStructureListLocked());
428 /* Remove us from the Process List */
429 RemoveEntryList(&CsrProcess
->ListLink
);
431 /* Release the lock */
432 CsrReleaseProcessLock();
434 /* Loop every Server DLL */
435 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
437 /* Get the Server DLL */
438 ServerDll
= CsrLoadedServerDll
[i
];
440 /* Check if it's valid and if it has a Disconnect Callback */
441 if (ServerDll
&& ServerDll
->DisconnectCallback
)
444 ServerDll
->DisconnectCallback(CsrProcess
);
450 * @name CsrInsertProcess
452 * The CsrInsertProcess routine inserts a CSR Process into the Process List
453 * and notifies Server DLLs of the creation of a new CSR Process.
455 * @param ParentProcess
456 * Optional pointer to the Parent Process creating this CSR Process.
459 * Pointer to the CSR Process which is to be inserted.
468 CsrInsertProcess(IN PCSR_PROCESS ParentProcess OPTIONAL
,
469 IN PCSR_PROCESS CsrProcess
)
471 PCSR_SERVER_DLL ServerDll
;
473 ASSERT(ProcessStructureListLocked());
475 /* Insert it into the Root List */
476 InsertTailList(&CsrRootProcess
->ListLink
, &CsrProcess
->ListLink
);
478 /* Notify the Server DLLs */
479 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
481 /* Get the current Server DLL */
482 ServerDll
= CsrLoadedServerDll
[i
];
484 /* Make sure it's valid and that it has callback */
485 if (ServerDll
&& ServerDll
->NewProcessCallback
)
487 ServerDll
->NewProcessCallback(ParentProcess
, CsrProcess
);
493 /* PUBLIC FUNCTIONS ***********************************************************/
496 * @name CsrCreateProcess
499 * The CsrCreateProcess routine creates a CSR Process object for an NT Process.
502 * Handle to an existing NT Process to which to associate this
506 * Handle to an existing NT Thread to which to create its
507 * corresponding CSR Thread for this CSR Process.
510 * Pointer to the Client ID structure of the NT Process to associate
511 * with this CSR Process.
517 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
524 CsrCreateProcess(IN HANDLE hProcess
,
526 IN PCLIENT_ID ClientId
,
527 IN PCSR_NT_SESSION NtSession
,
529 IN PCLIENT_ID DebugCid
)
531 PCSR_THREAD CurrentThread
= CsrGetClientThread();
532 CLIENT_ID CurrentCid
;
533 PCSR_PROCESS CurrentProcess
;
534 PCSR_SERVER_DLL ServerDll
;
537 PCSR_PROCESS CsrProcess
;
539 PCSR_THREAD CsrThread
;
540 KERNEL_USER_TIMES KernelTimes
;
542 /* Get the current CID and lock Processes */
543 CurrentCid
= CurrentThread
->ClientId
;
544 CsrAcquireProcessLock();
546 /* Get the current CSR Thread */
547 CurrentThread
= CsrLocateThreadByClientId(&CurrentProcess
, &CurrentCid
);
550 /* We've failed to locate the thread */
551 CsrReleaseProcessLock();
552 return STATUS_THREAD_IS_TERMINATING
;
555 /* Allocate a new Process Object */
556 CsrProcess
= CsrAllocateProcess();
559 /* Couldn't allocate Process */
560 CsrReleaseProcessLock();
561 return STATUS_NO_MEMORY
;
564 /* Inherit the Process Data */
565 CurrentProcess
= CurrentThread
->Process
;
566 ProcessData
= &CsrProcess
->ServerData
[CSR_SERVER_DLL_MAX
];
567 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
569 /* Get the current Server */
570 ServerDll
= CsrLoadedServerDll
[i
];
572 /* Check if the DLL is Loaded and has Per Process Data */
573 if (ServerDll
&& ServerDll
->SizeOfProcessData
)
575 /* Set the pointer */
576 CsrProcess
->ServerData
[i
] = ProcessData
;
579 RtlMoveMemory(ProcessData
,
580 CurrentProcess
->ServerData
[i
],
581 ServerDll
->SizeOfProcessData
);
583 /* Update next data pointer */
584 ProcessData
= (PVOID
)((ULONG_PTR
)ProcessData
+
585 ServerDll
->SizeOfProcessData
);
589 /* No data for this Server */
590 CsrProcess
->ServerData
[i
] = NULL
;
594 /* Set the Exception port for us */
595 Status
= NtSetInformationProcess(hProcess
,
596 ProcessExceptionPort
,
599 if (!NT_SUCCESS(Status
))
602 CsrDeallocateProcess(CsrProcess
);
603 CsrReleaseProcessLock();
604 return STATUS_NO_MEMORY
;
607 /* Check if CreateProcess got CREATE_NEW_PROCESS_GROUP */
608 if (Flags
& CsrProcessCreateNewGroup
)
611 * We create the process group leader of a new process group, therefore
612 * its process group ID and sequence number are its own ones.
614 CsrProcess
->ProcessGroupId
= HandleToUlong(ClientId
->UniqueProcess
);
615 CsrProcess
->ProcessGroupSequence
= CsrProcess
->SequenceNumber
;
619 /* Inherit the process group ID and sequence number from the current process */
620 CsrProcess
->ProcessGroupId
= CurrentProcess
->ProcessGroupId
;
621 CsrProcess
->ProcessGroupSequence
= CurrentProcess
->ProcessGroupSequence
;
624 /* Check if this is a console process */
625 if (Flags
& CsrProcessIsConsoleApp
) CsrProcess
->Flags
|= CsrProcessIsConsoleApp
;
627 /* Mask out non-debug flags */
628 Flags
&= ~(CsrProcessIsConsoleApp
| CsrProcessCreateNewGroup
| CsrProcessPriorityFlags
);
630 /* Check if every process will be debugged */
631 if (!(Flags
) && (CurrentProcess
->DebugFlags
& CsrDebugProcessChildren
))
633 /* Pass it on to the current process */
634 CsrProcess
->DebugFlags
= CsrDebugProcessChildren
;
635 CsrProcess
->DebugCid
= CurrentProcess
->DebugCid
;
638 /* Check if Debugging was used on this process */
639 if ((Flags
& (CsrDebugOnlyThisProcess
| CsrDebugProcessChildren
)) && (DebugCid
))
641 /* Save the debug flag used */
642 CsrProcess
->DebugFlags
= Flags
;
645 CsrProcess
->DebugCid
= *DebugCid
;
648 /* Check if Debugging is enabled */
649 if (CsrProcess
->DebugFlags
)
651 /* Set the Debug Port for us */
652 Status
= NtSetInformationProcess(hProcess
,
656 ASSERT(NT_SUCCESS(Status
));
657 if (!NT_SUCCESS(Status
))
660 CsrDeallocateProcess(CsrProcess
);
661 CsrReleaseProcessLock();
662 return STATUS_NO_MEMORY
;
666 /* Get the Thread Create Time */
667 Status
= NtQueryInformationThread(hThread
,
672 if (!NT_SUCCESS(Status
))
675 CsrDeallocateProcess(CsrProcess
);
676 CsrReleaseProcessLock();
677 return STATUS_NO_MEMORY
;
680 /* Allocate a CSR Thread Structure */
681 CsrThread
= CsrAllocateThread(CsrProcess
);
685 CsrDeallocateProcess(CsrProcess
);
686 CsrReleaseProcessLock();
687 return STATUS_NO_MEMORY
;
690 /* Save the data we have */
691 CsrThread
->CreateTime
= KernelTimes
.CreateTime
;
692 CsrThread
->ClientId
= *ClientId
;
693 CsrThread
->ThreadHandle
= hThread
;
694 ProtectHandle(hThread
);
695 CsrThread
->Flags
= 0;
697 /* Insert the Thread into the Process */
698 Status
= CsrInsertThread(CsrProcess
, CsrThread
);
699 if (!NT_SUCCESS(Status
))
702 CsrDeallocateProcess(CsrProcess
);
703 CsrDeallocateThread(CsrThread
);
704 CsrReleaseProcessLock();
708 /* Reference the session */
709 CsrReferenceNtSession(NtSession
);
710 CsrProcess
->NtSession
= NtSession
;
712 /* Setup Process Data */
713 CsrProcess
->ClientId
= *ClientId
;
714 CsrProcess
->ProcessHandle
= hProcess
;
715 CsrProcess
->ShutdownLevel
= 0x280;
717 /* Set the Priority to Background */
718 CsrSetBackgroundPriority(CsrProcess
);
720 /* Insert the Process */
721 CsrInsertProcess(CurrentProcess
, CsrProcess
);
723 /* Release lock and return */
724 CsrReleaseProcessLock();
729 * @name CsrDebugProcess
732 * The CsrDebugProcess routine is deprecated in NT 5.1 and higher. It is
733 * exported only for compatibility with older CSR Server DLLs.
740 * @remarks Deprecated.
745 CsrDebugProcess(IN PCSR_PROCESS CsrProcess
)
747 /* CSR does not handle debugging anymore */
748 DPRINT("CSRSRV: %s(0x%p) called\n", __FUNCTION__
, CsrProcess
);
749 return STATUS_UNSUCCESSFUL
;
753 * @name CsrDebugProcessStop
756 * The CsrDebugProcessStop routine is deprecated in NT 5.1 and higher. It is
757 * exported only for compatibility with older CSR Server DLLs.
764 * @remarks Deprecated.
769 CsrDebugProcessStop(IN PCSR_PROCESS CsrProcess
)
771 /* CSR does not handle debugging anymore */
772 DPRINT("CSRSRV: %s(0x%p) called\n", __FUNCTION__
, CsrProcess
);
773 return STATUS_UNSUCCESSFUL
;
777 * @name CsrDereferenceProcess
780 * The CsrDereferenceProcess routine removes a reference from a CSR Process.
783 * Pointer to the CSR Process to dereference.
787 * @remarks If the reference count has reached zero (ie: the CSR Process has
788 * no more active references), it will be deleted.
793 CsrDereferenceProcess(IN PCSR_PROCESS CsrProcess
)
797 /* Acquire process lock */
798 CsrAcquireProcessLock();
800 /* Decrease reference count */
801 LockCount
= --CsrProcess
->ReferenceCount
;
802 ASSERT(LockCount
>= 0);
805 /* Call the generic cleanup code */
806 CsrProcessRefcountZero(CsrProcess
);
810 /* Just release the lock */
811 CsrReleaseProcessLock();
816 * @name CsrDestroyProcess
819 * The CsrDestroyProcess routine destroys the CSR Process corresponding to
823 * Pointer to the Client ID Structure corresponding to the CSR
824 * Process which is about to be destroyed.
829 * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING
830 * if the CSR Process is already terminating.
837 CsrDestroyProcess(IN PCLIENT_ID Cid
,
838 IN NTSTATUS ExitStatus
)
840 PCSR_THREAD CsrThread
;
841 PCSR_PROCESS CsrProcess
;
842 CLIENT_ID ClientId
= *Cid
;
843 PLIST_ENTRY NextEntry
;
846 CsrAcquireProcessLock();
848 /* Find the thread */
849 CsrThread
= CsrLocateThreadByClientId(&CsrProcess
, &ClientId
);
851 /* Make sure we got one back, and that it's not already gone */
852 if (!(CsrThread
) || (CsrProcess
->Flags
& CsrProcessTerminating
))
854 /* Release the lock and return failure */
855 CsrReleaseProcessLock();
856 return STATUS_THREAD_IS_TERMINATING
;
859 /* Set the terminated flag */
860 CsrProcess
->Flags
|= CsrProcessTerminating
;
862 /* Get the List Pointers */
863 NextEntry
= CsrProcess
->ThreadList
.Flink
;
864 while (NextEntry
!= &CsrProcess
->ThreadList
)
866 /* Get the current thread entry */
867 CsrThread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
869 /* Move to the next entry */
870 NextEntry
= NextEntry
->Flink
;
872 /* Make sure the thread isn't already dead */
873 if (CsrThread
->Flags
& CsrThreadTerminated
)
875 /* Go the the next thread */
879 /* Set the Terminated flag */
880 CsrThread
->Flags
|= CsrThreadTerminated
;
882 /* Acquire the Wait Lock */
883 CsrAcquireWaitLock();
885 /* Do we have an active wait block? */
886 if (CsrThread
->WaitBlock
)
888 /* Notify waiters of termination */
889 CsrNotifyWaitBlock(CsrThread
->WaitBlock
,
893 CsrProcessTerminating
,
897 /* Release the Wait Lock */
898 CsrReleaseWaitLock();
900 /* Dereference the thread */
901 CsrLockedDereferenceThread(CsrThread
);
904 /* Release the Process Lock and return success */
905 CsrReleaseProcessLock();
906 return STATUS_SUCCESS
;
910 * @name CsrGetProcessLuid
913 * The CsrGetProcessLuid routine gets the LUID of the given process.
916 * Optional handle to the process whose LUID should be returned.
919 * Pointer to a LUID Pointer which will receive the CSR Process' LUID.
921 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
923 * @remarks If hProcess is not supplied, then the current thread's token will
924 * be used. If that too is missing, then the current process' token
930 CsrGetProcessLuid(IN HANDLE hProcess OPTIONAL
,
933 HANDLE hToken
= NULL
;
936 PTOKEN_STATISTICS TokenStats
;
938 /* Check if we have a handle to a CSR Process */
941 /* We don't, so try opening the Thread's Token */
942 Status
= NtOpenThreadToken(NtCurrentThread(),
947 /* Check for success */
948 if (!NT_SUCCESS(Status
))
950 /* If we got some other failure, then return and quit */
951 if (Status
!= STATUS_NO_TOKEN
) return Status
;
953 /* We don't have a Thread Token, use a Process Token */
954 hProcess
= NtCurrentProcess();
959 /* Check if we have a token by now */
962 /* No token yet, so open the Process Token */
963 Status
= NtOpenProcessToken(hProcess
,
966 if (!NT_SUCCESS(Status
))
968 /* Still no token, return the error */
973 /* Now get the size we'll need for the Token Information */
974 Status
= NtQueryInformationToken(hToken
,
980 /* Allocate memory for the Token Info */
981 if (!(TokenStats
= RtlAllocateHeap(CsrHeap
, 0, Length
)))
983 /* Fail and close the token */
985 return STATUS_NO_MEMORY
;
988 /* Now query the information */
989 Status
= NtQueryInformationToken(hToken
,
995 /* Close the handle */
998 /* Check for success */
999 if (NT_SUCCESS(Status
))
1001 /* Return the LUID */
1002 *Luid
= TokenStats
->AuthenticationId
;
1005 /* Free the query information */
1006 RtlFreeHeap(CsrHeap
, 0, TokenStats
);
1008 /* Return the Status */
1013 * @name CsrImpersonateClient
1016 * The CsrImpersonateClient will impersonate the given CSR Thread.
1019 * Pointer to the CSR Thread to impersonate.
1021 * @return TRUE if impersonation succeeded, FALSE otherwise.
1023 * @remarks Impersonation can be recursive.
1028 CsrImpersonateClient(IN PCSR_THREAD CsrThread
)
1031 PCSR_THREAD CurrentThread
= CsrGetClientThread();
1033 /* Use the current thread if none given */
1034 if (!CsrThread
) CsrThread
= CurrentThread
;
1036 /* Still no thread, something is wrong */
1044 Status
= NtImpersonateThread(NtCurrentThread(),
1045 CsrThread
->ThreadHandle
,
1048 if (!NT_SUCCESS(Status
))
1051 DPRINT1("CSRSS: Can't impersonate client thread - Status = %lx\n", Status
);
1052 // if (Status != STATUS_BAD_IMPERSONATION_LEVEL) DbgBreakPoint();
1056 /* Increase the impersonation count for the current thread */
1057 if (CurrentThread
) ++CurrentThread
->ImpersonationCount
;
1059 /* Return Success */
1064 * @name CsrLockProcessByClientId
1067 * The CsrLockProcessByClientId routine locks the CSR Process corresponding
1068 * to the given Process ID and optionally returns it.
1071 * Process ID corresponding to the CSR Process which will be locked.
1074 * Optional pointer to a CSR Process pointer which will hold the
1075 * CSR Process corresponding to the given Process ID.
1077 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
1079 * @remarks Locking a CSR Process is defined as acquiring an extra
1080 * reference to it and returning with the Process Lock held.
1085 CsrLockProcessByClientId(IN HANDLE Pid
,
1086 OUT PCSR_PROCESS
*CsrProcess
)
1088 PLIST_ENTRY NextEntry
;
1089 PCSR_PROCESS CurrentProcess
= NULL
;
1090 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1092 /* Acquire the lock */
1093 CsrAcquireProcessLock();
1095 /* Assume failure */
1096 ASSERT(CsrProcess
!= NULL
);
1099 /* Setup the List Pointers */
1100 NextEntry
= &CsrRootProcess
->ListLink
;
1103 /* Get the Process */
1104 CurrentProcess
= CONTAINING_RECORD(NextEntry
, CSR_PROCESS
, ListLink
);
1106 /* Check for PID Match */
1107 if (CurrentProcess
->ClientId
.UniqueProcess
== Pid
)
1109 Status
= STATUS_SUCCESS
;
1113 /* Move to the next entry */
1114 NextEntry
= NextEntry
->Flink
;
1115 } while (NextEntry
!= &CsrRootProcess
->ListLink
);
1117 /* Check if we didn't find it in the list */
1118 if (!NT_SUCCESS(Status
))
1120 /* Nothing found, release the lock */
1121 CsrReleaseProcessLock();
1125 /* Lock the found process and return it */
1126 CsrLockedReferenceProcess(CurrentProcess
);
1127 *CsrProcess
= CurrentProcess
;
1130 /* Return the result */
1135 * @name CsrRevertToSelf
1138 * The CsrRevertToSelf routine will attempt to remove an active impersonation.
1142 * @return TRUE if the reversion was succesful, FALSE otherwise.
1144 * @remarks Impersonation can be recursive; as such, the impersonation token
1145 * will only be deleted once the CSR Thread's impersonaton count
1151 CsrRevertToSelf(VOID
)
1154 PCSR_THREAD CurrentThread
= CsrGetClientThread();
1155 HANDLE ImpersonationToken
= NULL
;
1157 /* Check if we have a Current Thread */
1160 /* Make sure impersonation is on */
1161 if (!CurrentThread
->ImpersonationCount
)
1163 DPRINT1("CSRSS: CsrRevertToSelf called while not impersonating\n");
1167 else if ((--CurrentThread
->ImpersonationCount
) > 0)
1169 /* Success; impersonation count decreased but still not zero */
1174 /* Impersonation has been totally removed, revert to ourselves */
1175 Status
= NtSetInformationThread(NtCurrentThread(),
1176 ThreadImpersonationToken
,
1177 &ImpersonationToken
,
1180 /* Return TRUE or FALSE */
1181 return NT_SUCCESS(Status
);
1185 * @name CsrSetBackgroundPriority
1188 * The CsrSetBackgroundPriority routine sets the priority for the given CSR
1189 * Process as a Background priority.
1192 * Pointer to the CSR Process whose priority will be modified.
1201 CsrSetBackgroundPriority(IN PCSR_PROCESS CsrProcess
)
1203 PROCESS_PRIORITY_CLASS PriorityClass
;
1205 /* Set the Foreground bit off */
1206 PriorityClass
.Foreground
= FALSE
;
1208 /* Set the new Priority */
1209 NtSetInformationProcess(CsrProcess
->ProcessHandle
,
1210 ProcessPriorityClass
,
1212 sizeof(PriorityClass
));
1216 * @name CsrSetForegroundPriority
1219 * The CsrSetForegroundPriority routine sets the priority for the given CSR
1220 * Process as a Foreground priority.
1223 * Pointer to the CSR Process whose priority will be modified.
1232 CsrSetForegroundPriority(IN PCSR_PROCESS CsrProcess
)
1234 PROCESS_PRIORITY_CLASS PriorityClass
;
1236 /* Set the Foreground bit on */
1237 PriorityClass
.Foreground
= TRUE
;
1239 /* Set the new Priority */
1240 NtSetInformationProcess(CsrProcess
->ProcessHandle
,
1241 ProcessPriorityClass
,
1243 sizeof(PriorityClass
));
1247 * @name CsrShutdownProcesses
1250 * The CsrShutdownProcesses routine shuts down every CSR Process possible
1251 * and calls each Server DLL's shutdown notification.
1254 * Pointer to the LUID of the CSR Process that is ordering the
1258 * Flags to send to the shutdown notification routine.
1260 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
1267 CsrShutdownProcesses(IN PLUID CallerLuid
,
1270 PLIST_ENTRY NextEntry
;
1271 PCSR_PROCESS CsrProcess
;
1275 PCSR_SERVER_DLL ServerDll
;
1276 ULONG Result
= 0; /* Intentionally invalid enumeratee to silence compiler warning */
1278 /* Acquire process lock */
1279 CsrAcquireProcessLock();
1281 /* Add shutdown flag */
1282 CsrRootProcess
->ShutdownFlags
|= CsrShutdownSystem
;
1284 /* Get the list pointers */
1285 NextEntry
= CsrRootProcess
->ListLink
.Flink
;
1286 while (NextEntry
!= &CsrRootProcess
->ListLink
)
1288 /* Get the Process */
1289 CsrProcess
= CONTAINING_RECORD(NextEntry
, CSR_PROCESS
, ListLink
);
1291 /* Move to the next entry */
1292 NextEntry
= NextEntry
->Flink
;
1294 /* Remove the skip flag, set shutdown flags to 0 */
1295 CsrProcess
->Flags
&= ~CsrProcessSkipShutdown
;
1296 CsrProcess
->ShutdownFlags
= 0;
1299 /* Set shudown Priority */
1300 CsrSetToShutdownPriority();
1305 /* Find the next process to shutdown */
1306 CsrProcess
= FindProcessForShutdown(CallerLuid
);
1307 if (!CsrProcess
) break;
1309 /* Increase reference to process */
1310 CsrLockedReferenceProcess(CsrProcess
);
1315 /* Loop all the servers */
1316 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
1318 /* Get the current server */
1319 ServerDll
= CsrLoadedServerDll
[i
];
1321 /* Check if it's valid and if it has a Shutdown Process Callback */
1322 if (ServerDll
&& ServerDll
->ShutdownProcessCallback
)
1324 /* Release the lock, make the callback, and acquire it back */
1325 CsrReleaseProcessLock();
1326 Result
= ServerDll
->ShutdownProcessCallback(CsrProcess
,
1329 CsrAcquireProcessLock();
1331 /* Check the result */
1332 if (Result
== CsrShutdownCsrProcess
)
1334 /* The callback unlocked the process */
1337 else if (Result
== CsrShutdownCancelled
)
1339 /* Check if this was a forced shutdown */
1340 if (Flags
& EWX_FORCE
)
1342 DPRINT1("Process %x cancelled forced shutdown (Dll = %d)\n",
1343 CsrProcess
->ClientId
.UniqueProcess
, i
);
1347 /* Shutdown was cancelled, unlock and exit */
1348 CsrReleaseProcessLock();
1349 Status
= STATUS_CANCELLED
;
1355 /* No matches during the first try, so loop again */
1356 if ((FirstTry
) && (Result
== CsrShutdownNonCsrProcess
))
1362 /* Second try, break out */
1366 /* We've reached the final loop here, so dereference */
1367 if (i
== CSR_SERVER_DLL_MAX
) CsrLockedDereferenceProcess(CsrProcess
);
1371 CsrReleaseProcessLock();
1372 Status
= STATUS_SUCCESS
;
1375 /* Return to normal priority */
1376 CsrSetToNormalPriority();
1381 /* HACK: Temporary hack. This is really "CsrShutdownProcesses", mostly. Used by winsrv */
1385 CsrEnumProcesses(IN CSRSS_ENUM_PROCESS_PROC EnumProc
,
1388 PVOID
* RealContext
= (PVOID
*)Context
;
1389 PLUID CallerLuid
= RealContext
[0];
1390 PCSR_PROCESS CsrProcess
= NULL
;
1391 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1393 PLIST_ENTRY NextEntry
;
1396 /* Acquire process lock */
1397 CsrAcquireProcessLock();
1399 /* Get the list pointers */
1400 NextEntry
= CsrRootProcess
->ListLink
.Flink
;
1401 while (NextEntry
!= &CsrRootProcess
->ListLink
)
1403 /* Get the Process */
1404 CsrProcess
= CONTAINING_RECORD(NextEntry
, CSR_PROCESS
, ListLink
);
1406 /* Move to the next entry */
1407 NextEntry
= NextEntry
->Flink
;
1409 /* Remove the skip flag, set shutdown flags to 0 */
1410 CsrProcess
->Flags
&= ~CsrProcessSkipShutdown
;
1411 CsrProcess
->ShutdownFlags
= 0;
1414 /* Set shudown Priority */
1415 CsrSetToShutdownPriority();
1417 /* Loop all processes */
1418 //DPRINT1("Enumerating for LUID: %lx %lx\n", CallerLuid->HighPart, CallerLuid->LowPart);
1423 /* Find the next process to shutdown */
1425 if (!(CsrProcess
= FindProcessForShutdown(CallerLuid
)))
1428 CsrReleaseProcessLock();
1429 Status
= STATUS_SUCCESS
;
1434 /* Release the lock, make the callback, and acquire it back */
1435 //DPRINT1("Found process: %lx\n", CsrProcess->ClientId.UniqueProcess);
1436 CsrReleaseProcessLock();
1437 Result
= (ULONG
)EnumProc(CsrProcess
, (PVOID
)((ULONG_PTR
)Context
| FirstTry
));
1438 CsrAcquireProcessLock();
1440 /* Check the result */
1441 //DPRINT1("Result: %d\n", Result);
1442 if (Result
== CsrShutdownCsrProcess
)
1444 /* The callback unlocked the process */
1447 else if (Result
== CsrShutdownNonCsrProcess
)
1449 /* A non-CSR process, the callback didn't touch it */
1452 else if (Result
== CsrShutdownCancelled
)
1454 /* Shutdown was cancelled, unlock and exit */
1455 CsrReleaseProcessLock();
1456 Status
= STATUS_CANCELLED
;
1460 /* No matches during the first try, so loop again */
1461 if (FirstTry
&& Result
== CsrShutdownNonCsrProcess
)
1469 /* Return to normal priority */
1470 CsrSetToNormalPriority();
1476 * @name CsrUnlockProcess
1479 * The CsrUnlockProcess undoes a previous CsrLockProcessByClientId operation.
1482 * Pointer to a previously locked CSR Process.
1484 * @return STATUS_SUCCESS.
1486 * @remarks This routine must be called with the Process Lock held.
1491 CsrUnlockProcess(IN PCSR_PROCESS CsrProcess
)
1493 /* Dereference the process */
1494 CsrLockedDereferenceProcess(CsrProcess
);
1496 /* Release the lock and return */
1497 CsrReleaseProcessLock();
1498 return STATUS_SUCCESS
;