[CSRSRV]
[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 CsrpSetToNormalPriority
36 *
37 * The CsrpSetToNormalPriority 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) // CsrpSetToNormalPriority
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 CsrpSetToShutdownPriority
63 *
64 * The CsrpSetToShutdownPriority 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) // CsrpSetToShutdownPriority
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 CsrProcessRefcountZero(CsrProcess);
272 CsrAcquireProcessLock();
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 CsrProcess->ReferenceCount++;
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 = &CurrentProcess->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 /* Make sure the thread isn't already dead */
858 if (CsrThread->Flags & CsrThreadTerminated)
859 {
860 NextEntry = NextEntry->Flink;
861 continue;
862 }
863
864 /* Set the Terminated flag */
865 CsrThread->Flags |= CsrThreadTerminated;
866
867 /* Acquire the Wait Lock */
868 CsrAcquireWaitLock();
869
870 /* Do we have an active wait block? */
871 if (CsrThread->WaitBlock)
872 {
873 /* Notify waiters of termination */
874 CsrNotifyWaitBlock(CsrThread->WaitBlock,
875 NULL,
876 NULL,
877 NULL,
878 CsrProcessTerminating,
879 TRUE);
880 }
881
882 /* Release the Wait Lock */
883 CsrReleaseWaitLock();
884
885 /* Dereference the thread */
886 CsrLockedDereferenceThread(CsrThread);
887 NextEntry = CsrProcess->ThreadList.Flink;
888 }
889
890 /* Release the Process Lock and return success */
891 CsrReleaseProcessLock();
892 return STATUS_SUCCESS;
893 }
894
895 /*++
896 * @name CsrGetProcessLuid
897 * @implemented NT4
898 *
899 * Do nothing for 500ms.
900 *
901 * @param hProcess
902 * Optional handle to the process whose LUID should be returned.
903 *
904 * @param Luid
905 * Pointer to a LUID Pointer which will receive the CSR Process' LUID
906 *
907 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
908 * otherwise.
909 *
910 * @remarks If hProcess is not supplied, then the current thread's token will
911 * be used. If that too is missing, then the current process' token
912 * will be used.
913 *
914 *--*/
915 NTSTATUS
916 NTAPI
917 CsrGetProcessLuid(IN HANDLE hProcess OPTIONAL,
918 OUT PLUID Luid)
919 {
920 HANDLE hToken = NULL;
921 NTSTATUS Status;
922 ULONG Length;
923 PTOKEN_STATISTICS TokenStats;
924
925 /* Check if we have a handle to a CSR Process */
926 if (!hProcess)
927 {
928 /* We don't, so try opening the Thread's Token */
929 Status = NtOpenThreadToken(NtCurrentThread(),
930 TOKEN_QUERY,
931 FALSE,
932 &hToken);
933
934 /* Check for success */
935 if (!NT_SUCCESS(Status))
936 {
937 /* If we got some other failure, then return and quit */
938 if (Status != STATUS_NO_TOKEN) return Status;
939
940 /* We don't have a Thread Token, use a Process Token */
941 hProcess = NtCurrentProcess();
942 hToken = NULL;
943 }
944 }
945
946 /* Check if we have a token by now */
947 if (!hToken)
948 {
949 /* No token yet, so open the Process Token */
950 Status = NtOpenProcessToken(hProcess,
951 TOKEN_QUERY,
952 &hToken);
953 if (!NT_SUCCESS(Status))
954 {
955 /* Still no token, return the error */
956 return Status;
957 }
958 }
959
960 /* Now get the size we'll need for the Token Information */
961 Status = NtQueryInformationToken(hToken,
962 TokenStatistics,
963 NULL,
964 0,
965 &Length);
966
967 /* Allocate memory for the Token Info */
968 if (!(TokenStats = RtlAllocateHeap(CsrHeap, 0, Length)))
969 {
970 /* Fail and close the token */
971 NtClose(hToken);
972 return STATUS_NO_MEMORY;
973 }
974
975 /* Now query the information */
976 Status = NtQueryInformationToken(hToken,
977 TokenStatistics,
978 TokenStats,
979 Length,
980 &Length);
981
982 /* Close the handle */
983 NtClose(hToken);
984
985 /* Check for success */
986 if (NT_SUCCESS(Status))
987 {
988 /* Return the LUID */
989 *Luid = TokenStats->AuthenticationId;
990 }
991
992 /* Free the query information */
993 RtlFreeHeap(CsrHeap, 0, TokenStats);
994
995 /* Return the Status */
996 return Status;
997 }
998
999 /*++
1000 * @name CsrImpersonateClient
1001 * @implemented NT4
1002 *
1003 * The CsrImpersonateClient will impersonate the given CSR Thread.
1004 *
1005 * @param CsrThread
1006 * Pointer to the CSR Thread to impersonate.
1007 *
1008 * @return TRUE if impersionation suceeded, false otherwise.
1009 *
1010 * @remarks Impersonation can be recursive.
1011 *
1012 *--*/
1013 BOOLEAN
1014 NTAPI
1015 CsrImpersonateClient(IN PCSR_THREAD CsrThread)
1016 {
1017 NTSTATUS Status;
1018 PCSR_THREAD CurrentThread = CsrGetClientThread();
1019
1020 /* Use the current thread if none given */
1021 if (!CsrThread) CsrThread = CurrentThread;
1022
1023 /* Still no thread, something is wrong */
1024 if (!CsrThread)
1025 {
1026 /* Failure */
1027 return FALSE;
1028 }
1029
1030 /* Make the call */
1031 Status = NtImpersonateThread(NtCurrentThread(),
1032 CsrThread->ThreadHandle,
1033 &CsrSecurityQos);
1034
1035 if (!NT_SUCCESS(Status))
1036 {
1037 /* Failure */
1038 /*
1039 DPRINT1("CSRSS: Can't impersonate client thread - Status = %lx\n", Status);
1040 if (Status != STATUS_BAD_IMPERSONATION_LEVEL) DbgBreakPoint();
1041 */
1042 return FALSE;
1043 }
1044
1045 /* Increase the impersonation count for the current thread */
1046 if (CurrentThread) ++CurrentThread->ImpersonationCount;
1047
1048 /* Return Success */
1049 return TRUE;
1050 }
1051
1052 /*++
1053 * @name CsrLockProcessByClientId
1054 * @implemented NT4
1055 *
1056 * The CsrLockProcessByClientId routine locks the CSR Process corresponding
1057 * to the given Process ID and optionally returns it.
1058 *
1059 * @param Pid
1060 * Process ID corresponding to the CSR Process which will be locked.
1061 *
1062 * @param CsrProcess
1063 * Optional pointer to a CSR Process pointer which will hold the
1064 * CSR Process corresponding to the given Process ID.
1065 *
1066 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
1067 * otherwise.
1068 *
1069 * @remarks Locking a CSR Process is defined as acquiring an extra
1070 * reference to it and returning with the Process Lock held.
1071 *
1072 *--*/
1073 NTSTATUS
1074 NTAPI
1075 CsrLockProcessByClientId(IN HANDLE Pid,
1076 OUT PCSR_PROCESS *CsrProcess)
1077 {
1078 PLIST_ENTRY NextEntry;
1079 PCSR_PROCESS CurrentProcess = NULL;
1080 NTSTATUS Status;
1081
1082 /* Acquire the lock */
1083 CsrAcquireProcessLock();
1084
1085 /* Assume failure */
1086 ASSERT(CsrProcess != NULL);
1087 *CsrProcess = NULL;
1088
1089 /* Setup the List Pointers */
1090 NextEntry = &CsrRootProcess->ListLink;
1091 do
1092 {
1093 /* Get the Process */
1094 CurrentProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink);
1095
1096 /* Check for PID Match */
1097 if (CurrentProcess->ClientId.UniqueProcess == Pid)
1098 {
1099 Status = STATUS_SUCCESS;
1100 break;
1101 }
1102
1103 /* Next entry */
1104 NextEntry = NextEntry->Flink;
1105 } while (NextEntry != &CsrRootProcess->ListLink);
1106
1107 /* Check if we didn't find it in the list */
1108 if (!NT_SUCCESS(Status))
1109 {
1110 /* Nothing found, release the lock */
1111 CsrReleaseProcessLock();
1112 }
1113 else
1114 {
1115 /* Lock the found process and return it */
1116 CsrLockedReferenceProcess(CurrentProcess);
1117 *CsrProcess = CurrentProcess;
1118 }
1119
1120 /* Return the result */
1121 return Status;
1122 }
1123
1124 /*++
1125 * @name CsrRevertToSelf
1126 * @implemented NT4
1127 *
1128 * The CsrRevertToSelf routine will attempt to remove an active impersonation.
1129 *
1130 * @param None.
1131 *
1132 * @return TRUE if the reversion was succesful, false otherwise.
1133 *
1134 * @remarks Impersonation can be recursive; as such, the impersonation token
1135 * will only be deleted once the CSR Thread's impersonaton count
1136 * has reached zero.
1137 *
1138 *--*/
1139 BOOLEAN
1140 NTAPI
1141 CsrRevertToSelf(VOID)
1142 {
1143 NTSTATUS Status;
1144 PCSR_THREAD CurrentThread = CsrGetClientThread();
1145 HANDLE ImpersonationToken = NULL;
1146
1147 /* Check if we have a Current Thread */
1148 if (CurrentThread)
1149 {
1150 /* Make sure impersonation is on */
1151 if (!CurrentThread->ImpersonationCount)
1152 {
1153 // DPRINT1("CSRSS: CsrRevertToSelf called while not impersonating\n");
1154 // DbgBreakPoint();
1155 return FALSE;
1156 }
1157 else if (--CurrentThread->ImpersonationCount > 0)
1158 {
1159 /* Success; impersonation count decreased but still not zero */
1160 return TRUE;
1161 }
1162 }
1163
1164 /* Impersonation has been totally removed, revert to ourselves */
1165 Status = NtSetInformationThread(NtCurrentThread(),
1166 ThreadImpersonationToken,
1167 &ImpersonationToken,
1168 sizeof(HANDLE));
1169
1170 /* Return TRUE or FALSE */
1171 return NT_SUCCESS(Status);
1172 }
1173
1174 /*++
1175 * @name CsrSetBackgroundPriority
1176 * @implemented NT4
1177 *
1178 * The CsrSetBackgroundPriority routine sets the priority for the given CSR
1179 * Process as a Background priority.
1180 *
1181 * @param CsrProcess
1182 * Pointer to the CSR Process whose priority will be modified.
1183 *
1184 * @return None.
1185 *
1186 * @remarks None.
1187 *
1188 *--*/
1189 VOID
1190 NTAPI
1191 CsrSetBackgroundPriority(IN PCSR_PROCESS CsrProcess)
1192 {
1193 PROCESS_PRIORITY_CLASS PriorityClass;
1194
1195 /* Set the Foreground bit off */
1196 PriorityClass.Foreground = FALSE;
1197
1198 /* Set the new Priority */
1199 NtSetInformationProcess(CsrProcess->ProcessHandle,
1200 ProcessPriorityClass,
1201 &PriorityClass,
1202 sizeof(PriorityClass));
1203 }
1204
1205 /*++
1206 * @name CsrSetForegroundPriority
1207 * @implemented NT4
1208 *
1209 * The CsrSetForegroundPriority routine sets the priority for the given CSR
1210 * Process as a Foreground priority.
1211 *
1212 * @param CsrProcess
1213 * Pointer to the CSR Process whose priority will be modified.
1214 *
1215 * @return None.
1216 *
1217 * @remarks None.
1218 *
1219 *--*/
1220 VOID
1221 NTAPI
1222 CsrSetForegroundPriority(IN PCSR_PROCESS CsrProcess)
1223 {
1224 PROCESS_PRIORITY_CLASS PriorityClass;
1225
1226 /* Set the Foreground bit on */
1227 PriorityClass.Foreground = TRUE;
1228
1229 /* Set the new Priority */
1230 NtSetInformationProcess(CsrProcess->ProcessHandle,
1231 ProcessPriorityClass,
1232 &PriorityClass,
1233 sizeof(PriorityClass));
1234 }
1235
1236 /*++
1237 * @name CsrShutdownProcesses
1238 * @implemented NT4
1239 *
1240 * The CsrShutdownProcesses routine shuts down every CSR Process possible
1241 * and calls each Server DLL's shutdown notification.
1242 *
1243 * @param CallerLuid
1244 * Pointer to the LUID of the CSR Process that is ordering the
1245 * shutdown.
1246 *
1247 * @param Flags
1248 * Flags to send to the shutdown notification routine.
1249 *
1250 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
1251 * otherwise.
1252 *
1253 * @remarks None.
1254 *
1255 *--*/
1256 NTSTATUS
1257 NTAPI
1258 CsrShutdownProcesses(IN PLUID CallerLuid,
1259 IN ULONG Flags)
1260 {
1261 PLIST_ENTRY NextEntry;
1262 PCSR_PROCESS CsrProcess;
1263 NTSTATUS Status;
1264 BOOLEAN FirstTry;
1265 ULONG i;
1266 PCSR_SERVER_DLL ServerDll;
1267 ULONG Result = 0; /* Intentionally invalid enumeratee to silence compiler warning */
1268
1269 /* Acquire process lock */
1270 CsrAcquireProcessLock();
1271
1272 /* Add shutdown flag */
1273 CsrRootProcess->ShutdownFlags |= CsrShutdownSystem;
1274
1275 /* Get the list pointers */
1276 NextEntry = CsrRootProcess->ListLink.Flink;
1277 while (NextEntry != &CsrRootProcess->ListLink)
1278 {
1279 /* Get the Process */
1280 CsrProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink);
1281
1282 /* Remove the skip flag, set shutdown flags to 0*/
1283 CsrProcess->Flags &= ~CsrProcessSkipShutdown;
1284 CsrProcess->ShutdownFlags = 0;
1285
1286 /* Move to the next */
1287 NextEntry = NextEntry->Flink;
1288 }
1289
1290 /* Set shudown Priority */
1291 // CsrpSetToShutdownPriority();
1292 CsrSetToShutdownPriority();
1293
1294 /* Start looping */
1295 while (TRUE)
1296 {
1297 /* Find the next process to shutdown */
1298 CsrProcess = FindProcessForShutdown(CallerLuid);
1299 if (!CsrProcess) break;
1300
1301 /* Increase reference to process */
1302 CsrProcess->ReferenceCount++;
1303
1304 FirstTry = TRUE;
1305 while (TRUE)
1306 {
1307 /* Loop all the servers */
1308 for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
1309 {
1310 /* Get the current server */
1311 ServerDll = CsrLoadedServerDll[i];
1312
1313 /* Check if it's valid and if it has a Shutdown Process Callback */
1314 if (ServerDll && ServerDll->ShutdownProcessCallback)
1315 {
1316 /* Release the lock, make the callback, and acquire it back */
1317 CsrReleaseProcessLock();
1318 Result = ServerDll->ShutdownProcessCallback(CsrProcess,
1319 Flags,
1320 FirstTry);
1321 CsrAcquireProcessLock();
1322
1323 /* Check the result */
1324 if (Result == CsrShutdownCsrProcess)
1325 {
1326 /* The callback unlocked the process */
1327 break;
1328 }
1329 else if (Result == CsrShutdownCancelled)
1330 {
1331 /* Check if this was a forced shutdown */
1332 if (Flags & EWX_FORCE)
1333 {
1334 DPRINT1("Process %x cancelled forced shutdown (Dll = %d)\n",
1335 CsrProcess->ClientId.UniqueProcess, i);
1336 DbgBreakPoint();
1337 }
1338
1339 /* Shutdown was cancelled, unlock and exit */
1340 CsrReleaseProcessLock();
1341 Status = STATUS_CANCELLED;
1342 goto Quickie;
1343 }
1344 }
1345 }
1346
1347 /* No matches during the first try, so loop again */
1348 if ((FirstTry) && (Result == CsrShutdownNonCsrProcess))
1349 {
1350 FirstTry = FALSE;
1351 continue;
1352 }
1353
1354 /* Second try, break out */
1355 break;
1356 }
1357
1358 /* We've reached the final loop here, so dereference */
1359 if (i == CSR_SERVER_DLL_MAX) CsrLockedDereferenceProcess(CsrProcess);
1360 }
1361
1362 /* Success path */
1363 CsrReleaseProcessLock();
1364 Status = STATUS_SUCCESS;
1365
1366 Quickie:
1367 /* Return to normal priority */
1368 // CsrpSetToNormalPriority();
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 /* Remove the skip flag, set shutdown flags to 0*/
1400 CsrProcess->Flags &= ~CsrProcessSkipShutdown;
1401 CsrProcess->ShutdownFlags = 0;
1402
1403 /* Move to the next */
1404 NextEntry = NextEntry->Flink;
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 */