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