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