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