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 *******************************************************************/
17 /* GLOBALS ********************************************************************/
19 RTL_CRITICAL_SECTION CsrProcessLock
;
20 PCSR_PROCESS CsrRootProcess
= NULL
;
21 SECURITY_QUALITY_OF_SERVICE CsrSecurityQos
=
23 sizeof(SECURITY_QUALITY_OF_SERVICE
),
24 SecurityImpersonation
,
25 SECURITY_STATIC_TRACKING
,
28 ULONG CsrProcessSequenceCount
= 5;
29 extern ULONG CsrTotalPerProcessDataLength
;
32 /* PRIVATE FUNCTIONS **********************************************************/
35 * @name CsrSetToNormalPriority
37 * The CsrSetToNormalPriority routine sets the current NT Process'
38 * priority to the normal priority for CSR Processes.
44 * @remarks The "Normal" Priority corresponds to the Normal Foreground
45 * Priority (9) plus a boost of 4.
50 CsrSetToNormalPriority(VOID
)
52 KPRIORITY BasePriority
= (8 + 1) + 4;
54 /* Set the Priority */
55 NtSetInformationProcess(NtCurrentProcess(),
62 * @name CsrSetToShutdownPriority
64 * The CsrSetToShutdownPriority routine sets the current NT Process'
65 * priority to the boosted priority for CSR Processes doing shutdown.
66 * Additonally, it acquires the Shutdown Privilege required for shutdown.
72 * @remarks The "Shutdown" Priority corresponds to the Normal Foreground
73 * Priority (9) plus a boost of 6.
78 CsrSetToShutdownPriority(VOID
)
80 KPRIORITY SetBasePriority
= (8 + 1) + 6;
83 /* Get the shutdown privilege */
84 if (NT_SUCCESS(RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE
,
89 /* Set the Priority */
90 NtSetInformationProcess(NtCurrentProcess(),
98 * @name FindProcessForShutdown
100 * The FindProcessForShutdown routine returns a CSR Process which is ready
101 * to be shutdown, and sets the appropriate shutdown flags for it.
104 * Pointer to the LUID of the CSR Process calling this routine.
106 * @return Pointer to a CSR Process which is ready to be shutdown.
113 FindProcessForShutdown(IN PLUID CallerLuid
)
115 PCSR_PROCESS CsrProcess
, ReturnCsrProcess
= NULL
;
116 // PCSR_THREAD CsrThread;
120 LUID SystemLuid
= SYSTEM_LUID
;
121 // BOOLEAN IsSystemLuid = FALSE, IsOurLuid = FALSE;
122 PLIST_ENTRY NextEntry
;
124 /* Set the List Pointers */
125 NextEntry
= CsrRootProcess
->ListLink
.Flink
;
126 while (NextEntry
!= &CsrRootProcess
->ListLink
)
128 /* Get the process */
129 CsrProcess
= CONTAINING_RECORD(NextEntry
, CSR_PROCESS
, ListLink
);
131 /* Move to the next entry */
132 NextEntry
= NextEntry
->Flink
;
134 /* Skip this process if it's already been processed */
135 if (CsrProcess
->Flags
& CsrProcessSkipShutdown
) continue;
137 /* Get the LUID of this Process */
138 Status
= CsrGetProcessLuid(CsrProcess
->ProcessHandle
, &ProcessLuid
);
140 /* Check if we didn't get access to the LUID */
141 if (Status
== STATUS_ACCESS_DENIED
)
143 /* FIXME: Check if we have any threads */
145 /\* Check if we have any threads *\/
146 if (CsrProcess->ThreadCount)
148 /\* Impersonate one of the threads and retry *\/
149 CsrThread = CONTAINING_RECORD(CsrProcess->ThreadList.Flink,
152 CsrImpersonateClient(CsrThread);
153 Status = CsrGetProcessLuid(NULL, &ProcessLuid);
159 if (!NT_SUCCESS(Status
))
161 /* We didn't have access, so skip it */
162 CsrProcess
->Flags
|= CsrProcessSkipShutdown
;
166 /* Check if this is the System LUID */
167 if ((/*IsSystemLuid =*/ RtlEqualLuid(&ProcessLuid
, &SystemLuid
)))
169 /* Mark this process */
170 CsrProcess
->ShutdownFlags
|= CsrShutdownSystem
;
172 else if (!(/*IsOurLuid =*/ RtlEqualLuid(&ProcessLuid
, CallerLuid
)))
174 /* Our LUID doesn't match with the caller's */
175 CsrProcess
->ShutdownFlags
|= CsrShutdownOther
;
178 /* Check if we're past the previous level */
179 // FIXME: if ((CsrProcess->ShutdownLevel > Level) || !(ReturnCsrProcess))
180 if (CsrProcess
->ShutdownLevel
> Level
/* || !ReturnCsrProcess */)
182 /* Update the level */
183 Level
= CsrProcess
->ShutdownLevel
;
185 /* Set the final process */
186 ReturnCsrProcess
= CsrProcess
;
190 /* Check if we found a process */
191 if (ReturnCsrProcess
)
193 /* Skip this one next time */
194 ReturnCsrProcess
->Flags
|= CsrProcessSkipShutdown
;
197 return ReturnCsrProcess
;
201 * @name CsrProcessRefcountZero
203 * The CsrProcessRefcountZero routine is executed when a CSR Process has lost
204 * all its active references. It removes and de-allocates the CSR Process.
207 * Pointer to the CSR Process that is to be deleted.
211 * @remarks Do not call this routine. It is reserved for the internal
212 * thread management routines when a CSR Process has lost all
215 * This routine is called with the Process Lock held.
220 CsrProcessRefcountZero(IN PCSR_PROCESS CsrProcess
)
222 ASSERT(ProcessStructureListLocked());
224 /* Remove the Process from the list */
225 CsrRemoveProcess(CsrProcess
);
227 /* Check if there's a session */
228 if (CsrProcess
->NtSession
)
230 /* Dereference the Session */
231 CsrDereferenceNtSession(CsrProcess
->NtSession
, 0);
234 /* Close the Client Port if there is one */
235 if (CsrProcess
->ClientPort
) NtClose(CsrProcess
->ClientPort
);
237 /* Close the process handle */
238 NtClose(CsrProcess
->ProcessHandle
);
240 /* Free the Proces Object */
241 CsrDeallocateProcess(CsrProcess
);
245 * @name CsrLockedDereferenceProcess
247 * The CsrLockedDereferenceProcess dereferences a CSR Process while the
248 * Process Lock is already being held.
251 * Pointer to the CSR Process to be dereferenced.
255 * @remarks This routine will return with the Process Lock held.
260 CsrLockedDereferenceProcess(PCSR_PROCESS CsrProcess
)
264 /* Decrease reference count */
265 LockCount
= --CsrProcess
->ReferenceCount
;
266 ASSERT(LockCount
>= 0);
269 /* Call the generic cleanup code */
270 DPRINT1("Should kill process: %p\n", CsrProcess
);
271 CsrAcquireProcessLock();
272 CsrProcessRefcountZero(CsrProcess
);
277 * @name CsrAllocateProcess
280 * The CsrAllocateProcess routine allocates a new CSR Process object.
282 * @return Pointer to the newly allocated CSR Process.
289 CsrAllocateProcess(VOID
)
291 PCSR_PROCESS CsrProcess
;
294 /* Calculate the amount of memory this should take */
295 TotalSize
= sizeof(CSR_PROCESS
) +
296 (CSR_SERVER_DLL_MAX
* sizeof(PVOID
)) +
297 CsrTotalPerProcessDataLength
;
299 /* Allocate a Process */
300 CsrProcess
= RtlAllocateHeap(CsrHeap
, HEAP_ZERO_MEMORY
, TotalSize
);
301 if (!CsrProcess
) return NULL
;
303 /* Handle the Sequence Number and protect against overflow */
304 CsrProcess
->SequenceNumber
= CsrProcessSequenceCount
++;
305 if (CsrProcessSequenceCount
< 5) CsrProcessSequenceCount
= 5;
307 /* Increase the reference count */
308 CsrLockedReferenceProcess(CsrProcess
);
310 /* Initialize the Thread List */
311 InitializeListHead(&CsrProcess
->ThreadList
);
313 /* Return the Process */
318 * @name CsrLockedReferenceProcess
320 * The CsrLockedReferenceProcess references a CSR Process while the
321 * Process Lock is already being held.
324 * Pointer to the CSR Process to be referenced.
328 * @remarks This routine will return with the Process Lock held.
333 CsrLockedReferenceProcess(IN PCSR_PROCESS CsrProcess
)
335 /* Increment the reference count */
336 ++CsrProcess
->ReferenceCount
;
340 * @name CsrInitializeProcessStructure
343 * The CsrInitializeProcessStructure routine sets up support for CSR Processes
344 * and CSR Threads by initializing our own CSR Root Process.
348 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
355 CsrInitializeProcessStructure(VOID
)
360 /* Initialize the Lock */
361 Status
= RtlInitializeCriticalSection(&CsrProcessLock
);
362 if (!NT_SUCCESS(Status
)) return Status
;
364 /* Set up the Root Process */
365 CsrRootProcess
= CsrAllocateProcess();
366 if (!CsrRootProcess
) return STATUS_NO_MEMORY
;
368 /* Set up the minimal information for it */
369 InitializeListHead(&CsrRootProcess
->ListLink
);
370 CsrRootProcess
->ProcessHandle
= (HANDLE
)-1;
371 CsrRootProcess
->ClientId
= NtCurrentTeb()->ClientId
;
373 /* Initialize the Thread Hash List */
374 for (i
= 0; i
< NUMBER_THREAD_HASH_BUCKETS
; i
++) InitializeListHead(&CsrThreadHashTable
[i
]);
376 /* Initialize the Wait Lock */
377 return RtlInitializeCriticalSection(&CsrWaitListsLock
);
381 * @name CsrDeallocateProcess
383 * The CsrDeallocateProcess frees the memory associated with a CSR Process.
386 * Pointer to the CSR Process to be freed.
390 * @remarks Do not call this routine. It is reserved for the internal
391 * thread management routines when a CSR Process has been cleanly
392 * dereferenced and killed.
397 CsrDeallocateProcess(IN PCSR_PROCESS CsrProcess
)
399 /* Free the process object from the heap */
400 RtlFreeHeap(CsrHeap
, 0, CsrProcess
);
404 * @name CsrRemoveProcess
406 * The CsrRemoveProcess function undoes a CsrInsertProcess operation and
407 * removes the CSR Process from the Process List and notifies Server DLLs
411 * Pointer to the CSR Process to remove.
420 CsrRemoveProcess(IN PCSR_PROCESS CsrProcess
)
422 PCSR_SERVER_DLL ServerDll
;
424 ASSERT(ProcessStructureListLocked());
426 /* Remove us from the Process List */
427 RemoveEntryList(&CsrProcess
->ListLink
);
429 /* Release the lock */
430 CsrReleaseProcessLock();
432 /* Loop every Server DLL */
433 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
435 /* Get the Server DLL */
436 ServerDll
= CsrLoadedServerDll
[i
];
438 /* Check if it's valid and if it has a Disconnect Callback */
439 if (ServerDll
&& ServerDll
->DisconnectCallback
)
442 ServerDll
->DisconnectCallback(CsrProcess
);
448 * @name CsrInsertProcess
450 * The CsrInsertProcess routine inserts a CSR Process into the Process List
451 * and notifies Server DLLs of the creation of a new CSR Process.
453 * @param ParentProcess
454 * Optional pointer to the Parent Process creating this CSR Process.
457 * Pointer to the CSR Process which is to be inserted.
466 CsrInsertProcess(IN PCSR_PROCESS ParentProcess OPTIONAL
,
467 IN PCSR_PROCESS CsrProcess
)
469 PCSR_SERVER_DLL ServerDll
;
471 ASSERT(ProcessStructureListLocked());
473 /* Insert it into the Root List */
474 InsertTailList(&CsrRootProcess
->ListLink
, &CsrProcess
->ListLink
);
476 /* Notify the Server DLLs */
477 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
479 /* Get the current Server DLL */
480 ServerDll
= CsrLoadedServerDll
[i
];
482 /* Make sure it's valid and that it has callback */
483 if (ServerDll
&& ServerDll
->NewProcessCallback
)
485 ServerDll
->NewProcessCallback(ParentProcess
, CsrProcess
);
491 /* PUBLIC FUNCTIONS ***********************************************************/
494 * @name CsrCreateProcess
497 * The CsrCreateProcess routine creates a CSR Process object for an NT Process.
500 * Handle to an existing NT Process to which to associate this
504 * Handle to an existing NT Thread to which to create its
505 * corresponding CSR Thread for this CSR Process.
508 * Pointer to the Client ID structure of the NT Process to associate
509 * with this CSR Process.
515 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
522 CsrCreateProcess(IN HANDLE hProcess
,
524 IN PCLIENT_ID ClientId
,
525 IN PCSR_NT_SESSION NtSession
,
527 IN PCLIENT_ID DebugCid
)
529 PCSR_THREAD CurrentThread
= CsrGetClientThread();
530 CLIENT_ID CurrentCid
;
531 PCSR_PROCESS CurrentProcess
;
532 PCSR_SERVER_DLL ServerDll
;
535 PCSR_PROCESS CsrProcess
;
537 PCSR_THREAD CsrThread
;
538 KERNEL_USER_TIMES KernelTimes
;
540 /* Get the current CID and lock Processes */
541 CurrentCid
= CurrentThread
->ClientId
;
542 CsrAcquireProcessLock();
544 /* Get the current CSR Thread */
545 CurrentThread
= CsrLocateThreadByClientId(&CurrentProcess
, &CurrentCid
);
548 /* We've failed to locate the thread */
549 CsrReleaseProcessLock();
550 return STATUS_THREAD_IS_TERMINATING
;
553 /* Allocate a new Process Object */
554 CsrProcess
= CsrAllocateProcess();
557 /* Couldn't allocate Process */
558 CsrReleaseProcessLock();
559 return STATUS_NO_MEMORY
;
562 /* Inherit the Process Data */
563 CurrentProcess
= CurrentThread
->Process
;
564 ProcessData
= &CsrProcess
->ServerData
[CSR_SERVER_DLL_MAX
];
565 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
567 /* Get the current Server */
568 ServerDll
= CsrLoadedServerDll
[i
];
570 /* Check if the DLL is Loaded and has Per Process Data */
571 if (ServerDll
&& ServerDll
->SizeOfProcessData
)
573 /* Set the pointer */
574 CsrProcess
->ServerData
[i
] = ProcessData
;
577 RtlMoveMemory(ProcessData
,
578 CurrentProcess
->ServerData
[i
],
579 ServerDll
->SizeOfProcessData
);
581 /* Update next data pointer */
582 ProcessData
= (PVOID
)((ULONG_PTR
)ProcessData
+
583 ServerDll
->SizeOfProcessData
);
587 /* No data for this Server */
588 CsrProcess
->ServerData
[i
] = NULL
;
592 /* Set the Exception port for us */
593 Status
= NtSetInformationProcess(hProcess
,
594 ProcessExceptionPort
,
597 if (!NT_SUCCESS(Status
))
600 CsrDeallocateProcess(CsrProcess
);
601 CsrReleaseProcessLock();
602 return STATUS_NO_MEMORY
;
605 /* Check if CreateProcess got CREATE_NEW_PROCESS_GROUP */
606 if ((Flags
& CsrProcessCreateNewGroup
) == 0)
608 /* Create new data */
609 CsrProcess
->ProcessGroupId
= HandleToUlong(ClientId
->UniqueProcess
);
610 CsrProcess
->ProcessGroupSequence
= CsrProcess
->SequenceNumber
;
614 /* Copy it from the current process */
615 CsrProcess
->ProcessGroupId
= CurrentProcess
->ProcessGroupId
;
616 CsrProcess
->ProcessGroupSequence
= CurrentProcess
->ProcessGroupSequence
;
619 /* Check if this is a console process */
620 if (Flags
& CsrProcessIsConsoleApp
) CsrProcess
->Flags
|= CsrProcessIsConsoleApp
;
622 /* Mask out non-debug flags */
623 Flags
&= ~(CsrProcessIsConsoleApp
| CsrProcessCreateNewGroup
| CsrProcessPriorityFlags
);
625 /* Check if every process will be debugged */
626 if (!(Flags
) && (CurrentProcess
->DebugFlags
& CsrDebugProcessChildren
))
628 /* Pass it on to the current process */
629 CsrProcess
->DebugFlags
= CsrDebugProcessChildren
;
630 CsrProcess
->DebugCid
= CurrentProcess
->DebugCid
;
633 /* Check if Debugging was used on this process */
634 if ((Flags
& (CsrDebugOnlyThisProcess
| CsrDebugProcessChildren
)) && (DebugCid
))
636 /* Save the debug flag used */
637 CsrProcess
->DebugFlags
= Flags
;
640 CsrProcess
->DebugCid
= *DebugCid
;
643 /* Check if Debugging is enabled */
644 if (CsrProcess
->DebugFlags
)
646 /* Set the Debug Port for us */
647 Status
= NtSetInformationProcess(hProcess
,
651 ASSERT(NT_SUCCESS(Status
));
652 if (!NT_SUCCESS(Status
))
655 CsrDeallocateProcess(CsrProcess
);
656 CsrReleaseProcessLock();
657 return STATUS_NO_MEMORY
;
661 /* Get the Thread Create Time */
662 Status
= NtQueryInformationThread(hThread
,
667 if (!NT_SUCCESS(Status
))
670 CsrDeallocateProcess(CsrProcess
);
671 CsrReleaseProcessLock();
672 return STATUS_NO_MEMORY
;
675 /* Allocate a CSR Thread Structure */
676 CsrThread
= CsrAllocateThread(CsrProcess
);
680 CsrDeallocateProcess(CsrProcess
);
681 CsrReleaseProcessLock();
682 return STATUS_NO_MEMORY
;
685 /* Save the data we have */
686 CsrThread
->CreateTime
= KernelTimes
.CreateTime
;
687 CsrThread
->ClientId
= *ClientId
;
688 CsrThread
->ThreadHandle
= hThread
;
689 ProtectHandle(hThread
);
690 CsrThread
->Flags
= 0;
692 /* Insert the Thread into the Process */
693 Status
= CsrInsertThread(CsrProcess
, CsrThread
);
694 if (!NT_SUCCESS(Status
))
697 CsrDeallocateProcess(CsrProcess
);
698 CsrDeallocateThread(CsrThread
);
699 CsrReleaseProcessLock();
703 /* Reference the session */
704 CsrReferenceNtSession(NtSession
);
705 CsrProcess
->NtSession
= NtSession
;
707 /* Setup Process Data */
708 CsrProcess
->ClientId
= *ClientId
;
709 CsrProcess
->ProcessHandle
= hProcess
;
710 CsrProcess
->ShutdownLevel
= 0x280;
712 /* Set the Priority to Background */
713 CsrSetBackgroundPriority(CsrProcess
);
715 /* Insert the Process */
716 CsrInsertProcess(CurrentProcess
, CsrProcess
);
718 /* Release lock and return */
719 CsrReleaseProcessLock();
724 * @name CsrDebugProcess
727 * The CsrDebugProcess routine is deprecated in NT 5.1 and higher. It is
728 * exported only for compatibility with older CSR Server DLLs.
735 * @remarks Deprecated.
740 CsrDebugProcess(IN PCSR_PROCESS CsrProcess
)
742 /* CSR does not handle debugging anymore */
743 DPRINT("CSRSRV: %s(0x%p) called\n", __FUNCTION__
, CsrProcess
);
744 return STATUS_UNSUCCESSFUL
;
748 * @name CsrDebugProcessStop
751 * The CsrDebugProcessStop routine is deprecated in NT 5.1 and higher. It is
752 * exported only for compatibility with older CSR Server DLLs.
759 * @remarks Deprecated.
764 CsrDebugProcessStop(IN PCSR_PROCESS CsrProcess
)
766 /* CSR does not handle debugging anymore */
767 DPRINT("CSRSRV: %s(0x%p) called\n", __FUNCTION__
, CsrProcess
);
768 return STATUS_UNSUCCESSFUL
;
772 * @name CsrDereferenceProcess
775 * The CsrDereferenceProcess routine removes a reference from a CSR Process.
778 * Pointer to the CSR Process to dereference.
782 * @remarks If the reference count has reached zero (ie: the CSR Process has
783 * no more active references), it will be deleted.
788 CsrDereferenceProcess(IN PCSR_PROCESS CsrProcess
)
792 /* Acquire process lock */
793 CsrAcquireProcessLock();
795 /* Decrease reference count */
796 LockCount
= --CsrProcess
->ReferenceCount
;
797 ASSERT(LockCount
>= 0);
800 /* Call the generic cleanup code */
801 CsrProcessRefcountZero(CsrProcess
);
805 /* Just release the lock */
806 CsrReleaseProcessLock();
811 * @name CsrDestroyProcess
814 * The CsrDestroyProcess routine destroys the CSR Process corresponding to
818 * Pointer to the Client ID Structure corresponding to the CSR
819 * Process which is about to be destroyed.
824 * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING
825 * if the CSR Process is already terminating.
832 CsrDestroyProcess(IN PCLIENT_ID Cid
,
833 IN NTSTATUS ExitStatus
)
835 PCSR_THREAD CsrThread
;
836 PCSR_PROCESS CsrProcess
;
837 CLIENT_ID ClientId
= *Cid
;
838 PLIST_ENTRY NextEntry
;
841 CsrAcquireProcessLock();
843 /* Find the thread */
844 CsrThread
= CsrLocateThreadByClientId(&CsrProcess
, &ClientId
);
846 /* Make sure we got one back, and that it's not already gone */
847 if (!(CsrThread
) || (CsrProcess
->Flags
& CsrProcessTerminating
))
849 /* Release the lock and return failure */
850 CsrReleaseProcessLock();
851 return STATUS_THREAD_IS_TERMINATING
;
854 /* Set the terminated flag */
855 CsrProcess
->Flags
|= CsrProcessTerminating
;
857 /* Get the List Pointers */
858 NextEntry
= CsrProcess
->ThreadList
.Flink
;
859 while (NextEntry
!= &CsrProcess
->ThreadList
)
861 /* Get the current thread entry */
862 CsrThread
= CONTAINING_RECORD(NextEntry
, CSR_THREAD
, Link
);
864 /* Move to the next entry */
865 NextEntry
= NextEntry
->Flink
;
867 /* Make sure the thread isn't already dead */
868 if (CsrThread
->Flags
& CsrThreadTerminated
)
870 /* Go the the next thread */
874 /* Set the Terminated flag */
875 CsrThread
->Flags
|= CsrThreadTerminated
;
877 /* Acquire the Wait Lock */
878 CsrAcquireWaitLock();
880 /* Do we have an active wait block? */
881 if (CsrThread
->WaitBlock
)
883 /* Notify waiters of termination */
884 CsrNotifyWaitBlock(CsrThread
->WaitBlock
,
888 CsrProcessTerminating
,
892 /* Release the Wait Lock */
893 CsrReleaseWaitLock();
895 /* Dereference the thread */
896 CsrLockedDereferenceThread(CsrThread
);
899 /* Release the Process Lock and return success */
900 CsrReleaseProcessLock();
901 return STATUS_SUCCESS
;
905 * @name CsrGetProcessLuid
908 * The CsrGetProcessLuid routine gets the LUID of the given process.
911 * Optional handle to the process whose LUID should be returned.
914 * Pointer to a LUID Pointer which will receive the CSR Process' LUID.
916 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
918 * @remarks If hProcess is not supplied, then the current thread's token will
919 * be used. If that too is missing, then the current process' token
925 CsrGetProcessLuid(IN HANDLE hProcess OPTIONAL
,
928 HANDLE hToken
= NULL
;
931 PTOKEN_STATISTICS TokenStats
;
933 /* Check if we have a handle to a CSR Process */
936 /* We don't, so try opening the Thread's Token */
937 Status
= NtOpenThreadToken(NtCurrentThread(),
942 /* Check for success */
943 if (!NT_SUCCESS(Status
))
945 /* If we got some other failure, then return and quit */
946 if (Status
!= STATUS_NO_TOKEN
) return Status
;
948 /* We don't have a Thread Token, use a Process Token */
949 hProcess
= NtCurrentProcess();
954 /* Check if we have a token by now */
957 /* No token yet, so open the Process Token */
958 Status
= NtOpenProcessToken(hProcess
,
961 if (!NT_SUCCESS(Status
))
963 /* Still no token, return the error */
968 /* Now get the size we'll need for the Token Information */
969 Status
= NtQueryInformationToken(hToken
,
975 /* Allocate memory for the Token Info */
976 if (!(TokenStats
= RtlAllocateHeap(CsrHeap
, 0, Length
)))
978 /* Fail and close the token */
980 return STATUS_NO_MEMORY
;
983 /* Now query the information */
984 Status
= NtQueryInformationToken(hToken
,
990 /* Close the handle */
993 /* Check for success */
994 if (NT_SUCCESS(Status
))
996 /* Return the LUID */
997 *Luid
= TokenStats
->AuthenticationId
;
1000 /* Free the query information */
1001 RtlFreeHeap(CsrHeap
, 0, TokenStats
);
1003 /* Return the Status */
1008 * @name CsrImpersonateClient
1011 * The CsrImpersonateClient will impersonate the given CSR Thread.
1014 * Pointer to the CSR Thread to impersonate.
1016 * @return TRUE if impersonation succeeded, FALSE otherwise.
1018 * @remarks Impersonation can be recursive.
1023 CsrImpersonateClient(IN PCSR_THREAD CsrThread
)
1026 PCSR_THREAD CurrentThread
= CsrGetClientThread();
1028 /* Use the current thread if none given */
1029 if (!CsrThread
) CsrThread
= CurrentThread
;
1031 /* Still no thread, something is wrong */
1039 Status
= NtImpersonateThread(NtCurrentThread(),
1040 CsrThread
->ThreadHandle
,
1043 if (!NT_SUCCESS(Status
))
1046 DPRINT1("CSRSS: Can't impersonate client thread - Status = %lx\n", Status
);
1047 // if (Status != STATUS_BAD_IMPERSONATION_LEVEL) DbgBreakPoint();
1051 /* Increase the impersonation count for the current thread */
1052 if (CurrentThread
) ++CurrentThread
->ImpersonationCount
;
1054 /* Return Success */
1059 * @name CsrLockProcessByClientId
1062 * The CsrLockProcessByClientId routine locks the CSR Process corresponding
1063 * to the given Process ID and optionally returns it.
1066 * Process ID corresponding to the CSR Process which will be locked.
1069 * Optional pointer to a CSR Process pointer which will hold the
1070 * CSR Process corresponding to the given Process ID.
1072 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
1074 * @remarks Locking a CSR Process is defined as acquiring an extra
1075 * reference to it and returning with the Process Lock held.
1080 CsrLockProcessByClientId(IN HANDLE Pid
,
1081 OUT PCSR_PROCESS
*CsrProcess
)
1083 PLIST_ENTRY NextEntry
;
1084 PCSR_PROCESS CurrentProcess
= NULL
;
1085 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1087 /* Acquire the lock */
1088 CsrAcquireProcessLock();
1090 /* Assume failure */
1091 ASSERT(CsrProcess
!= NULL
);
1094 /* Setup the List Pointers */
1095 NextEntry
= &CsrRootProcess
->ListLink
;
1098 /* Get the Process */
1099 CurrentProcess
= CONTAINING_RECORD(NextEntry
, CSR_PROCESS
, ListLink
);
1101 /* Check for PID Match */
1102 if (CurrentProcess
->ClientId
.UniqueProcess
== Pid
)
1104 Status
= STATUS_SUCCESS
;
1108 /* Move to the next entry */
1109 NextEntry
= NextEntry
->Flink
;
1110 } while (NextEntry
!= &CsrRootProcess
->ListLink
);
1112 /* Check if we didn't find it in the list */
1113 if (!NT_SUCCESS(Status
))
1115 /* Nothing found, release the lock */
1116 CsrReleaseProcessLock();
1120 /* Lock the found process and return it */
1121 CsrLockedReferenceProcess(CurrentProcess
);
1122 *CsrProcess
= CurrentProcess
;
1125 /* Return the result */
1130 * @name CsrRevertToSelf
1133 * The CsrRevertToSelf routine will attempt to remove an active impersonation.
1137 * @return TRUE if the reversion was succesful, FALSE otherwise.
1139 * @remarks Impersonation can be recursive; as such, the impersonation token
1140 * will only be deleted once the CSR Thread's impersonaton count
1146 CsrRevertToSelf(VOID
)
1149 PCSR_THREAD CurrentThread
= CsrGetClientThread();
1150 HANDLE ImpersonationToken
= NULL
;
1152 /* Check if we have a Current Thread */
1155 /* Make sure impersonation is on */
1156 if (!CurrentThread
->ImpersonationCount
)
1158 DPRINT1("CSRSS: CsrRevertToSelf called while not impersonating\n");
1162 else if ((--CurrentThread
->ImpersonationCount
) > 0)
1164 /* Success; impersonation count decreased but still not zero */
1169 /* Impersonation has been totally removed, revert to ourselves */
1170 Status
= NtSetInformationThread(NtCurrentThread(),
1171 ThreadImpersonationToken
,
1172 &ImpersonationToken
,
1175 /* Return TRUE or FALSE */
1176 return NT_SUCCESS(Status
);
1180 * @name CsrSetBackgroundPriority
1183 * The CsrSetBackgroundPriority routine sets the priority for the given CSR
1184 * Process as a Background priority.
1187 * Pointer to the CSR Process whose priority will be modified.
1196 CsrSetBackgroundPriority(IN PCSR_PROCESS CsrProcess
)
1198 PROCESS_PRIORITY_CLASS PriorityClass
;
1200 /* Set the Foreground bit off */
1201 PriorityClass
.Foreground
= FALSE
;
1203 /* Set the new Priority */
1204 NtSetInformationProcess(CsrProcess
->ProcessHandle
,
1205 ProcessPriorityClass
,
1207 sizeof(PriorityClass
));
1211 * @name CsrSetForegroundPriority
1214 * The CsrSetForegroundPriority routine sets the priority for the given CSR
1215 * Process as a Foreground priority.
1218 * Pointer to the CSR Process whose priority will be modified.
1227 CsrSetForegroundPriority(IN PCSR_PROCESS CsrProcess
)
1229 PROCESS_PRIORITY_CLASS PriorityClass
;
1231 /* Set the Foreground bit on */
1232 PriorityClass
.Foreground
= TRUE
;
1234 /* Set the new Priority */
1235 NtSetInformationProcess(CsrProcess
->ProcessHandle
,
1236 ProcessPriorityClass
,
1238 sizeof(PriorityClass
));
1242 * @name CsrShutdownProcesses
1245 * The CsrShutdownProcesses routine shuts down every CSR Process possible
1246 * and calls each Server DLL's shutdown notification.
1249 * Pointer to the LUID of the CSR Process that is ordering the
1253 * Flags to send to the shutdown notification routine.
1255 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
1262 CsrShutdownProcesses(IN PLUID CallerLuid
,
1265 PLIST_ENTRY NextEntry
;
1266 PCSR_PROCESS CsrProcess
;
1270 PCSR_SERVER_DLL ServerDll
;
1271 ULONG Result
= 0; /* Intentionally invalid enumeratee to silence compiler warning */
1273 /* Acquire process lock */
1274 CsrAcquireProcessLock();
1276 /* Add shutdown flag */
1277 CsrRootProcess
->ShutdownFlags
|= CsrShutdownSystem
;
1279 /* Get the list pointers */
1280 NextEntry
= CsrRootProcess
->ListLink
.Flink
;
1281 while (NextEntry
!= &CsrRootProcess
->ListLink
)
1283 /* Get the Process */
1284 CsrProcess
= CONTAINING_RECORD(NextEntry
, CSR_PROCESS
, ListLink
);
1286 /* Move to the next entry */
1287 NextEntry
= NextEntry
->Flink
;
1289 /* Remove the skip flag, set shutdown flags to 0 */
1290 CsrProcess
->Flags
&= ~CsrProcessSkipShutdown
;
1291 CsrProcess
->ShutdownFlags
= 0;
1294 /* Set shudown Priority */
1295 CsrSetToShutdownPriority();
1300 /* Find the next process to shutdown */
1301 CsrProcess
= FindProcessForShutdown(CallerLuid
);
1302 if (!CsrProcess
) break;
1304 /* Increase reference to process */
1305 CsrLockedReferenceProcess(CsrProcess
);
1310 /* Loop all the servers */
1311 for (i
= 0; i
< CSR_SERVER_DLL_MAX
; i
++)
1313 /* Get the current server */
1314 ServerDll
= CsrLoadedServerDll
[i
];
1316 /* Check if it's valid and if it has a Shutdown Process Callback */
1317 if (ServerDll
&& ServerDll
->ShutdownProcessCallback
)
1319 /* Release the lock, make the callback, and acquire it back */
1320 CsrReleaseProcessLock();
1321 Result
= ServerDll
->ShutdownProcessCallback(CsrProcess
,
1324 CsrAcquireProcessLock();
1326 /* Check the result */
1327 if (Result
== CsrShutdownCsrProcess
)
1329 /* The callback unlocked the process */
1332 else if (Result
== CsrShutdownCancelled
)
1334 /* Check if this was a forced shutdown */
1335 if (Flags
& EWX_FORCE
)
1337 DPRINT1("Process %x cancelled forced shutdown (Dll = %d)\n",
1338 CsrProcess
->ClientId
.UniqueProcess
, i
);
1342 /* Shutdown was cancelled, unlock and exit */
1343 CsrReleaseProcessLock();
1344 Status
= STATUS_CANCELLED
;
1350 /* No matches during the first try, so loop again */
1351 if ((FirstTry
) && (Result
== CsrShutdownNonCsrProcess
))
1357 /* Second try, break out */
1361 /* We've reached the final loop here, so dereference */
1362 if (i
== CSR_SERVER_DLL_MAX
) CsrLockedDereferenceProcess(CsrProcess
);
1366 CsrReleaseProcessLock();
1367 Status
= STATUS_SUCCESS
;
1370 /* Return to normal priority */
1371 CsrSetToNormalPriority();
1376 /* HACK: Temporary hack. This is really "CsrShutdownProcesses", mostly. Used by winsrv */
1380 CsrEnumProcesses(IN CSRSS_ENUM_PROCESS_PROC EnumProc
,
1383 PVOID
* RealContext
= (PVOID
*)Context
;
1384 PLUID CallerLuid
= RealContext
[0];
1385 PCSR_PROCESS CsrProcess
= NULL
;
1386 NTSTATUS Status
= STATUS_UNSUCCESSFUL
;
1388 PLIST_ENTRY NextEntry
;
1391 /* Acquire process lock */
1392 CsrAcquireProcessLock();
1394 /* Get the list pointers */
1395 NextEntry
= CsrRootProcess
->ListLink
.Flink
;
1396 while (NextEntry
!= &CsrRootProcess
->ListLink
)
1398 /* Get the Process */
1399 CsrProcess
= CONTAINING_RECORD(NextEntry
, CSR_PROCESS
, ListLink
);
1401 /* Move to the next entry */
1402 NextEntry
= NextEntry
->Flink
;
1404 /* Remove the skip flag, set shutdown flags to 0 */
1405 CsrProcess
->Flags
&= ~CsrProcessSkipShutdown
;
1406 CsrProcess
->ShutdownFlags
= 0;
1409 /* Set shudown Priority */
1410 CsrSetToShutdownPriority();
1412 /* Loop all processes */
1413 //DPRINT1("Enumerating for LUID: %lx %lx\n", CallerLuid->HighPart, CallerLuid->LowPart);
1418 /* Find the next process to shutdown */
1420 if (!(CsrProcess
= FindProcessForShutdown(CallerLuid
)))
1423 CsrReleaseProcessLock();
1424 Status
= STATUS_SUCCESS
;
1429 /* Release the lock, make the callback, and acquire it back */
1430 //DPRINT1("Found process: %lx\n", CsrProcess->ClientId.UniqueProcess);
1431 CsrReleaseProcessLock();
1432 Result
= (ULONG
)EnumProc(CsrProcess
, (PVOID
)((ULONG_PTR
)Context
| FirstTry
));
1433 CsrAcquireProcessLock();
1435 /* Check the result */
1436 //DPRINT1("Result: %d\n", Result);
1437 if (Result
== CsrShutdownCsrProcess
)
1439 /* The callback unlocked the process */
1442 else if (Result
== CsrShutdownNonCsrProcess
)
1444 /* A non-CSR process, the callback didn't touch it */
1447 else if (Result
== CsrShutdownCancelled
)
1449 /* Shutdown was cancelled, unlock and exit */
1450 CsrReleaseProcessLock();
1451 Status
= STATUS_CANCELLED
;
1455 /* No matches during the first try, so loop again */
1456 if (FirstTry
&& Result
== CsrShutdownNonCsrProcess
)
1464 /* Return to normal priority */
1465 CsrSetToNormalPriority();
1471 * @name CsrUnlockProcess
1474 * The CsrUnlockProcess undoes a previous CsrLockProcessByClientId operation.
1477 * Pointer to a previously locked CSR Process.
1479 * @return STATUS_SUCCESS.
1481 * @remarks This routine must be called with the Process Lock held.
1486 CsrUnlockProcess(IN PCSR_PROCESS CsrProcess
)
1488 /* Dereference the process */
1489 CsrLockedDereferenceProcess(CsrProcess
);
1491 /* Release the lock and return */
1492 CsrReleaseProcessLock();
1493 return STATUS_SUCCESS
;