def775e8025e4e613b2a50ee93be06efafa1bfa1
[reactos.git] / reactos / 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 Foreground
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 Foreground
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 == 0)
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 otherwise.
349 *
350 * @remarks None.
351 *
352 *--*/
353 NTSTATUS
354 NTAPI
355 CsrInitializeProcessStructure(VOID)
356 {
357 NTSTATUS Status;
358 ULONG i;
359
360 /* Initialize the Lock */
361 Status = RtlInitializeCriticalSection(&CsrProcessLock);
362 if (!NT_SUCCESS(Status)) return Status;
363
364 /* Set up the Root Process */
365 CsrRootProcess = CsrAllocateProcess();
366 if (!CsrRootProcess) return STATUS_NO_MEMORY;
367
368 /* Set up the minimal information for it */
369 InitializeListHead(&CsrRootProcess->ListLink);
370 CsrRootProcess->ProcessHandle = (HANDLE)-1;
371 CsrRootProcess->ClientId = NtCurrentTeb()->ClientId;
372
373 /* Initialize the Thread Hash List */
374 for (i = 0; i < NUMBER_THREAD_HASH_BUCKETS; i++) InitializeListHead(&CsrThreadHashTable[i]);
375
376 /* Initialize the Wait Lock */
377 return RtlInitializeCriticalSection(&CsrWaitListsLock);
378 }
379
380 /*++
381 * @name CsrDeallocateProcess
382 *
383 * The CsrDeallocateProcess frees the memory associated with a CSR Process.
384 *
385 * @param CsrProcess
386 * Pointer to the CSR Process to be freed.
387 *
388 * @return None.
389 *
390 * @remarks Do not call this routine. It is reserved for the internal
391 * thread management routines when a CSR Process has been cleanly
392 * dereferenced and killed.
393 *
394 *--*/
395 VOID
396 NTAPI
397 CsrDeallocateProcess(IN PCSR_PROCESS CsrProcess)
398 {
399 /* Free the process object from the heap */
400 RtlFreeHeap(CsrHeap, 0, CsrProcess);
401 }
402
403 /*++
404 * @name CsrRemoveProcess
405 *
406 * The CsrRemoveProcess function undoes a CsrInsertProcess operation and
407 * removes the CSR Process from the Process List and notifies Server DLLs
408 * of this removal.
409 *
410 * @param CsrProcess
411 * Pointer to the CSR Process to remove.
412 *
413 * @return None.
414 *
415 * @remarks None.
416 *
417 *--*/
418 VOID
419 NTAPI
420 CsrRemoveProcess(IN PCSR_PROCESS CsrProcess)
421 {
422 PCSR_SERVER_DLL ServerDll;
423 ULONG i;
424 ASSERT(ProcessStructureListLocked());
425
426 /* Remove us from the Process List */
427 RemoveEntryList(&CsrProcess->ListLink);
428
429 /* Release the lock */
430 CsrReleaseProcessLock();
431
432 /* Loop every Server DLL */
433 for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
434 {
435 /* Get the Server DLL */
436 ServerDll = CsrLoadedServerDll[i];
437
438 /* Check if it's valid and if it has a Disconnect Callback */
439 if (ServerDll && ServerDll->DisconnectCallback)
440 {
441 /* Call it */
442 ServerDll->DisconnectCallback(CsrProcess);
443 }
444 }
445 }
446
447 /*++
448 * @name CsrInsertProcess
449 *
450 * The CsrInsertProcess routine inserts a CSR Process into the Process List
451 * and notifies Server DLLs of the creation of a new CSR Process.
452 *
453 * @param ParentProcess
454 * Optional pointer to the Parent Process creating this CSR Process.
455 *
456 * @param CsrProcess
457 * Pointer to the CSR Process which is to be inserted.
458 *
459 * @return None.
460 *
461 * @remarks None.
462 *
463 *--*/
464 VOID
465 NTAPI
466 CsrInsertProcess(IN PCSR_PROCESS ParentProcess OPTIONAL,
467 IN PCSR_PROCESS CsrProcess)
468 {
469 PCSR_SERVER_DLL ServerDll;
470 ULONG i;
471 ASSERT(ProcessStructureListLocked());
472
473 /* Insert it into the Root List */
474 InsertTailList(&CsrRootProcess->ListLink, &CsrProcess->ListLink);
475
476 /* Notify the Server DLLs */
477 for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
478 {
479 /* Get the current Server DLL */
480 ServerDll = CsrLoadedServerDll[i];
481
482 /* Make sure it's valid and that it has callback */
483 if (ServerDll && ServerDll->NewProcessCallback)
484 {
485 ServerDll->NewProcessCallback(ParentProcess, CsrProcess);
486 }
487 }
488 }
489
490
491 /* PUBLIC FUNCTIONS ***********************************************************/
492
493 /*++
494 * @name CsrCreateProcess
495 * @implemented NT4
496 *
497 * The CsrCreateProcess routine creates a CSR Process object for an NT Process.
498 *
499 * @param hProcess
500 * Handle to an existing NT Process to which to associate this
501 * CSR Process.
502 *
503 * @param hThread
504 * Handle to an existing NT Thread to which to create its
505 * corresponding CSR Thread for this CSR Process.
506 *
507 * @param ClientId
508 * Pointer to the Client ID structure of the NT Process to associate
509 * with this CSR Process.
510 *
511 * @param NtSession
512 * @param Flags
513 * @param DebugCid
514 *
515 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
516 *
517 * @remarks None.
518 *
519 *--*/
520 NTSTATUS
521 NTAPI
522 CsrCreateProcess(IN HANDLE hProcess,
523 IN HANDLE hThread,
524 IN PCLIENT_ID ClientId,
525 IN PCSR_NT_SESSION NtSession,
526 IN ULONG Flags,
527 IN PCLIENT_ID DebugCid)
528 {
529 PCSR_THREAD CurrentThread = CsrGetClientThread();
530 CLIENT_ID CurrentCid;
531 PCSR_PROCESS CurrentProcess;
532 PCSR_SERVER_DLL ServerDll;
533 PVOID ProcessData;
534 ULONG i;
535 PCSR_PROCESS CsrProcess;
536 NTSTATUS Status;
537 PCSR_THREAD CsrThread;
538 KERNEL_USER_TIMES KernelTimes;
539
540 /* Get the current CID and lock Processes */
541 CurrentCid = CurrentThread->ClientId;
542 CsrAcquireProcessLock();
543
544 /* Get the current CSR Thread */
545 CurrentThread = CsrLocateThreadByClientId(&CurrentProcess, &CurrentCid);
546 if (!CurrentThread)
547 {
548 /* We've failed to locate the thread */
549 CsrReleaseProcessLock();
550 return STATUS_THREAD_IS_TERMINATING;
551 }
552
553 /* Allocate a new Process Object */
554 CsrProcess = CsrAllocateProcess();
555 if (!CsrProcess)
556 {
557 /* Couldn't allocate Process */
558 CsrReleaseProcessLock();
559 return STATUS_NO_MEMORY;
560 }
561
562 /* Inherit the Process Data */
563 CurrentProcess = CurrentThread->Process;
564 ProcessData = &CsrProcess->ServerData[CSR_SERVER_DLL_MAX];
565 for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
566 {
567 /* Get the current Server */
568 ServerDll = CsrLoadedServerDll[i];
569
570 /* Check if the DLL is Loaded and has Per Process Data */
571 if (ServerDll && ServerDll->SizeOfProcessData)
572 {
573 /* Set the pointer */
574 CsrProcess->ServerData[i] = ProcessData;
575
576 /* Copy the Data */
577 RtlMoveMemory(ProcessData,
578 CurrentProcess->ServerData[i],
579 ServerDll->SizeOfProcessData);
580
581 /* Update next data pointer */
582 ProcessData = (PVOID)((ULONG_PTR)ProcessData +
583 ServerDll->SizeOfProcessData);
584 }
585 else
586 {
587 /* No data for this Server */
588 CsrProcess->ServerData[i] = NULL;
589 }
590 }
591
592 /* Set the Exception port for us */
593 Status = NtSetInformationProcess(hProcess,
594 ProcessExceptionPort,
595 &CsrApiPort,
596 sizeof(HANDLE));
597 if (!NT_SUCCESS(Status))
598 {
599 /* Failed */
600 CsrDeallocateProcess(CsrProcess);
601 CsrReleaseProcessLock();
602 return STATUS_NO_MEMORY;
603 }
604
605 /* Check if CreateProcess got CREATE_NEW_PROCESS_GROUP */
606 if ((Flags & CsrProcessCreateNewGroup) == 0)
607 {
608 /* Create new data */
609 CsrProcess->ProcessGroupId = HandleToUlong(ClientId->UniqueProcess);
610 CsrProcess->ProcessGroupSequence = CsrProcess->SequenceNumber;
611 }
612 else
613 {
614 /* Copy it from the current process */
615 CsrProcess->ProcessGroupId = CurrentProcess->ProcessGroupId;
616 CsrProcess->ProcessGroupSequence = CurrentProcess->ProcessGroupSequence;
617 }
618
619 /* Check if this is a console process */
620 if (Flags & CsrProcessIsConsoleApp) CsrProcess->Flags |= CsrProcessIsConsoleApp;
621
622 /* Mask out non-debug flags */
623 Flags &= ~(CsrProcessIsConsoleApp | CsrProcessCreateNewGroup | CsrProcessPriorityFlags);
624
625 /* Check if every process will be debugged */
626 if (!(Flags) && (CurrentProcess->DebugFlags & CsrDebugProcessChildren))
627 {
628 /* Pass it on to the current process */
629 CsrProcess->DebugFlags = CsrDebugProcessChildren;
630 CsrProcess->DebugCid = CurrentProcess->DebugCid;
631 }
632
633 /* Check if Debugging was used on this process */
634 if ((Flags & (CsrDebugOnlyThisProcess | CsrDebugProcessChildren)) && (DebugCid))
635 {
636 /* Save the debug flag used */
637 CsrProcess->DebugFlags = Flags;
638
639 /* Save the CID */
640 CsrProcess->DebugCid = *DebugCid;
641 }
642
643 /* Check if Debugging is enabled */
644 if (CsrProcess->DebugFlags)
645 {
646 /* Set the Debug Port for us */
647 Status = NtSetInformationProcess(hProcess,
648 ProcessDebugPort,
649 &CsrApiPort,
650 sizeof(HANDLE));
651 ASSERT(NT_SUCCESS(Status));
652 if (!NT_SUCCESS(Status))
653 {
654 /* Failed */
655 CsrDeallocateProcess(CsrProcess);
656 CsrReleaseProcessLock();
657 return STATUS_NO_MEMORY;
658 }
659 }
660
661 /* Get the Thread Create Time */
662 Status = NtQueryInformationThread(hThread,
663 ThreadTimes,
664 (PVOID)&KernelTimes,
665 sizeof(KernelTimes),
666 NULL);
667 if (!NT_SUCCESS(Status))
668 {
669 /* Failed */
670 CsrDeallocateProcess(CsrProcess);
671 CsrReleaseProcessLock();
672 return STATUS_NO_MEMORY;
673 }
674
675 /* Allocate a CSR Thread Structure */
676 CsrThread = CsrAllocateThread(CsrProcess);
677 if (!CsrThread)
678 {
679 /* Failed */
680 CsrDeallocateProcess(CsrProcess);
681 CsrReleaseProcessLock();
682 return STATUS_NO_MEMORY;
683 }
684
685 /* Save the data we have */
686 CsrThread->CreateTime = KernelTimes.CreateTime;
687 CsrThread->ClientId = *ClientId;
688 CsrThread->ThreadHandle = hThread;
689 ProtectHandle(hThread);
690 CsrThread->Flags = 0;
691
692 /* Insert the Thread into the Process */
693 Status = CsrInsertThread(CsrProcess, CsrThread);
694 if (!NT_SUCCESS(Status))
695 {
696 /* Bail out */
697 CsrDeallocateProcess(CsrProcess);
698 CsrDeallocateThread(CsrThread);
699 CsrReleaseProcessLock();
700 return Status;
701 }
702
703 /* Reference the session */
704 CsrReferenceNtSession(NtSession);
705 CsrProcess->NtSession = NtSession;
706
707 /* Setup Process Data */
708 CsrProcess->ClientId = *ClientId;
709 CsrProcess->ProcessHandle = hProcess;
710 CsrProcess->ShutdownLevel = 0x280;
711
712 /* Set the Priority to Background */
713 CsrSetBackgroundPriority(CsrProcess);
714
715 /* Insert the Process */
716 CsrInsertProcess(CurrentProcess, CsrProcess);
717
718 /* Release lock and return */
719 CsrReleaseProcessLock();
720 return Status;
721 }
722
723 /*++
724 * @name CsrDebugProcess
725 * @implemented NT4
726 *
727 * The CsrDebugProcess routine is deprecated in NT 5.1 and higher. It is
728 * exported only for compatibility with older CSR Server DLLs.
729 *
730 * @param CsrProcess
731 * Deprecated.
732 *
733 * @return Deprecated
734 *
735 * @remarks Deprecated.
736 *
737 *--*/
738 NTSTATUS
739 NTAPI
740 CsrDebugProcess(IN PCSR_PROCESS CsrProcess)
741 {
742 /* CSR does not handle debugging anymore */
743 DPRINT("CSRSRV: %s(%08lx) called\n", __FUNCTION__, CsrProcess);
744 return STATUS_UNSUCCESSFUL;
745 }
746
747 /*++
748 * @name CsrDebugProcessStop
749 * @implemented NT4
750 *
751 * The CsrDebugProcessStop routine is deprecated in NT 5.1 and higher. It is
752 * exported only for compatibility with older CSR Server DLLs.
753 *
754 * @param CsrProcess
755 * Deprecated.
756 *
757 * @return Deprecated
758 *
759 * @remarks Deprecated.
760 *
761 *--*/
762 NTSTATUS
763 NTAPI
764 CsrDebugProcessStop(IN PCSR_PROCESS CsrProcess)
765 {
766 /* CSR does not handle debugging anymore */
767 DPRINT("CSRSRV: %s(%08lx) called\n", __FUNCTION__, CsrProcess);
768 return STATUS_UNSUCCESSFUL;
769 }
770
771 /*++
772 * @name CsrDereferenceProcess
773 * @implemented NT4
774 *
775 * The CsrDereferenceProcess routine removes a reference from a CSR Process.
776 *
777 * @param CsrThread
778 * Pointer to the CSR Process to dereference.
779 *
780 * @return None.
781 *
782 * @remarks If the reference count has reached zero (ie: the CSR Process has
783 * no more active references), it will be deleted.
784 *
785 *--*/
786 VOID
787 NTAPI
788 CsrDereferenceProcess(IN PCSR_PROCESS CsrProcess)
789 {
790 LONG LockCount;
791
792 /* Acquire process lock */
793 CsrAcquireProcessLock();
794
795 /* Decrease reference count */
796 LockCount = --CsrProcess->ReferenceCount;
797 ASSERT(LockCount >= 0);
798 if (LockCount == 0)
799 {
800 /* Call the generic cleanup code */
801 CsrProcessRefcountZero(CsrProcess);
802 }
803 else
804 {
805 /* Just release the lock */
806 CsrReleaseProcessLock();
807 }
808 }
809
810 /*++
811 * @name CsrDestroyProcess
812 * @implemented NT4
813 *
814 * The CsrDestroyProcess routine destroys the CSR Process corresponding to
815 * a given Client ID.
816 *
817 * @param Cid
818 * Pointer to the Client ID Structure corresponding to the CSR
819 * Process which is about to be destroyed.
820 *
821 * @param ExitStatus
822 * Unused.
823 *
824 * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING
825 * if the CSR Process is already terminating.
826 *
827 * @remarks None.
828 *
829 *--*/
830 NTSTATUS
831 NTAPI
832 CsrDestroyProcess(IN PCLIENT_ID Cid,
833 IN NTSTATUS ExitStatus)
834 {
835 PCSR_THREAD CsrThread;
836 PCSR_PROCESS CsrProcess;
837 CLIENT_ID ClientId = *Cid;
838 PLIST_ENTRY NextEntry;
839
840 /* Acquire lock */
841 CsrAcquireProcessLock();
842
843 /* Find the thread */
844 CsrThread = CsrLocateThreadByClientId(&CsrProcess, &ClientId);
845
846 /* Make sure we got one back, and that it's not already gone */
847 if (!(CsrThread) || (CsrProcess->Flags & CsrProcessTerminating))
848 {
849 /* Release the lock and return failure */
850 CsrReleaseProcessLock();
851 return STATUS_THREAD_IS_TERMINATING;
852 }
853
854 /* Set the terminated flag */
855 CsrProcess->Flags |= CsrProcessTerminating;
856
857 /* Get the List Pointers */
858 NextEntry = CsrProcess->ThreadList.Flink;
859 while (NextEntry != &CsrProcess->ThreadList)
860 {
861 /* Get the current thread entry */
862 CsrThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
863
864 /* Move to the next entry */
865 NextEntry = NextEntry->Flink;
866
867 /* Make sure the thread isn't already dead */
868 if (CsrThread->Flags & CsrThreadTerminated)
869 {
870 /* Go the the next thread */
871 continue;
872 }
873
874 /* Set the Terminated flag */
875 CsrThread->Flags |= CsrThreadTerminated;
876
877 /* Acquire the Wait Lock */
878 CsrAcquireWaitLock();
879
880 /* Do we have an active wait block? */
881 if (CsrThread->WaitBlock)
882 {
883 /* Notify waiters of termination */
884 CsrNotifyWaitBlock(CsrThread->WaitBlock,
885 NULL,
886 NULL,
887 NULL,
888 CsrProcessTerminating,
889 TRUE);
890 }
891
892 /* Release the Wait Lock */
893 CsrReleaseWaitLock();
894
895 /* Dereference the thread */
896 CsrLockedDereferenceThread(CsrThread);
897 }
898
899 /* Release the Process Lock and return success */
900 CsrReleaseProcessLock();
901 return STATUS_SUCCESS;
902 }
903
904 /*++
905 * @name CsrGetProcessLuid
906 * @implemented NT4
907 *
908 * The CsrGetProcessLuid routine gets the LUID of the given process.
909 *
910 * @param hProcess
911 * Optional handle to the process whose LUID should be returned.
912 *
913 * @param Luid
914 * Pointer to a LUID Pointer which will receive the CSR Process' LUID.
915 *
916 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
917 *
918 * @remarks If hProcess is not supplied, then the current thread's token will
919 * be used. If that too is missing, then the current process' token
920 * will be used.
921 *
922 *--*/
923 NTSTATUS
924 NTAPI
925 CsrGetProcessLuid(IN HANDLE hProcess OPTIONAL,
926 OUT PLUID Luid)
927 {
928 HANDLE hToken = NULL;
929 NTSTATUS Status;
930 ULONG Length;
931 PTOKEN_STATISTICS TokenStats;
932
933 /* Check if we have a handle to a CSR Process */
934 if (!hProcess)
935 {
936 /* We don't, so try opening the Thread's Token */
937 Status = NtOpenThreadToken(NtCurrentThread(),
938 TOKEN_QUERY,
939 FALSE,
940 &hToken);
941
942 /* Check for success */
943 if (!NT_SUCCESS(Status))
944 {
945 /* If we got some other failure, then return and quit */
946 if (Status != STATUS_NO_TOKEN) return Status;
947
948 /* We don't have a Thread Token, use a Process Token */
949 hProcess = NtCurrentProcess();
950 hToken = NULL;
951 }
952 }
953
954 /* Check if we have a token by now */
955 if (!hToken)
956 {
957 /* No token yet, so open the Process Token */
958 Status = NtOpenProcessToken(hProcess,
959 TOKEN_QUERY,
960 &hToken);
961 if (!NT_SUCCESS(Status))
962 {
963 /* Still no token, return the error */
964 return Status;
965 }
966 }
967
968 /* Now get the size we'll need for the Token Information */
969 Status = NtQueryInformationToken(hToken,
970 TokenStatistics,
971 NULL,
972 0,
973 &Length);
974
975 /* Allocate memory for the Token Info */
976 if (!(TokenStats = RtlAllocateHeap(CsrHeap, 0, Length)))
977 {
978 /* Fail and close the token */
979 NtClose(hToken);
980 return STATUS_NO_MEMORY;
981 }
982
983 /* Now query the information */
984 Status = NtQueryInformationToken(hToken,
985 TokenStatistics,
986 TokenStats,
987 Length,
988 &Length);
989
990 /* Close the handle */
991 NtClose(hToken);
992
993 /* Check for success */
994 if (NT_SUCCESS(Status))
995 {
996 /* Return the LUID */
997 *Luid = TokenStats->AuthenticationId;
998 }
999
1000 /* Free the query information */
1001 RtlFreeHeap(CsrHeap, 0, TokenStats);
1002
1003 /* Return the Status */
1004 return Status;
1005 }
1006
1007 /*++
1008 * @name CsrImpersonateClient
1009 * @implemented NT4
1010 *
1011 * The CsrImpersonateClient will impersonate the given CSR Thread.
1012 *
1013 * @param CsrThread
1014 * Pointer to the CSR Thread to impersonate.
1015 *
1016 * @return TRUE if impersonation succeeded, FALSE otherwise.
1017 *
1018 * @remarks Impersonation can be recursive.
1019 *
1020 *--*/
1021 BOOLEAN
1022 NTAPI
1023 CsrImpersonateClient(IN PCSR_THREAD CsrThread)
1024 {
1025 NTSTATUS Status;
1026 PCSR_THREAD CurrentThread = CsrGetClientThread();
1027
1028 /* Use the current thread if none given */
1029 if (!CsrThread) CsrThread = CurrentThread;
1030
1031 /* Still no thread, something is wrong */
1032 if (!CsrThread)
1033 {
1034 /* Failure */
1035 return FALSE;
1036 }
1037
1038 /* Make the call */
1039 Status = NtImpersonateThread(NtCurrentThread(),
1040 CsrThread->ThreadHandle,
1041 &CsrSecurityQos);
1042
1043 if (!NT_SUCCESS(Status))
1044 {
1045 /* Failure */
1046 DPRINT1("CSRSS: Can't impersonate client thread - Status = %lx\n", Status);
1047 // if (Status != STATUS_BAD_IMPERSONATION_LEVEL) DbgBreakPoint();
1048 return FALSE;
1049 }
1050
1051 /* Increase the impersonation count for the current thread */
1052 if (CurrentThread) ++CurrentThread->ImpersonationCount;
1053
1054 /* Return Success */
1055 return TRUE;
1056 }
1057
1058 /*++
1059 * @name CsrLockProcessByClientId
1060 * @implemented NT4
1061 *
1062 * The CsrLockProcessByClientId routine locks the CSR Process corresponding
1063 * to the given Process ID and optionally returns it.
1064 *
1065 * @param Pid
1066 * Process ID corresponding to the CSR Process which will be locked.
1067 *
1068 * @param CsrProcess
1069 * Optional pointer to a CSR Process pointer which will hold the
1070 * CSR Process corresponding to the given Process ID.
1071 *
1072 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
1073 *
1074 * @remarks Locking a CSR Process is defined as acquiring an extra
1075 * reference to it and returning with the Process Lock held.
1076 *
1077 *--*/
1078 NTSTATUS
1079 NTAPI
1080 CsrLockProcessByClientId(IN HANDLE Pid,
1081 OUT PCSR_PROCESS *CsrProcess)
1082 {
1083 PLIST_ENTRY NextEntry;
1084 PCSR_PROCESS CurrentProcess = NULL;
1085 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1086
1087 /* Acquire the lock */
1088 CsrAcquireProcessLock();
1089
1090 /* Assume failure */
1091 ASSERT(CsrProcess != NULL);
1092 *CsrProcess = NULL;
1093
1094 /* Setup the List Pointers */
1095 NextEntry = &CsrRootProcess->ListLink;
1096 do
1097 {
1098 /* Get the Process */
1099 CurrentProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink);
1100
1101 /* Check for PID Match */
1102 if (CurrentProcess->ClientId.UniqueProcess == Pid)
1103 {
1104 Status = STATUS_SUCCESS;
1105 break;
1106 }
1107
1108 /* Move to the next entry */
1109 NextEntry = NextEntry->Flink;
1110 } while (NextEntry != &CsrRootProcess->ListLink);
1111
1112 /* Check if we didn't find it in the list */
1113 if (!NT_SUCCESS(Status))
1114 {
1115 /* Nothing found, release the lock */
1116 CsrReleaseProcessLock();
1117 }
1118 else
1119 {
1120 /* Lock the found process and return it */
1121 CsrLockedReferenceProcess(CurrentProcess);
1122 *CsrProcess = CurrentProcess;
1123 }
1124
1125 /* Return the result */
1126 return Status;
1127 }
1128
1129 /*++
1130 * @name CsrRevertToSelf
1131 * @implemented NT4
1132 *
1133 * The CsrRevertToSelf routine will attempt to remove an active impersonation.
1134 *
1135 * @param None.
1136 *
1137 * @return TRUE if the reversion was succesful, FALSE otherwise.
1138 *
1139 * @remarks Impersonation can be recursive; as such, the impersonation token
1140 * will only be deleted once the CSR Thread's impersonaton count
1141 * has reached zero.
1142 *
1143 *--*/
1144 BOOLEAN
1145 NTAPI
1146 CsrRevertToSelf(VOID)
1147 {
1148 NTSTATUS Status;
1149 PCSR_THREAD CurrentThread = CsrGetClientThread();
1150 HANDLE ImpersonationToken = NULL;
1151
1152 /* Check if we have a Current Thread */
1153 if (CurrentThread)
1154 {
1155 /* Make sure impersonation is on */
1156 if (!CurrentThread->ImpersonationCount)
1157 {
1158 DPRINT1("CSRSS: CsrRevertToSelf called while not impersonating\n");
1159 // DbgBreakPoint();
1160 return FALSE;
1161 }
1162 else if ((--CurrentThread->ImpersonationCount) > 0)
1163 {
1164 /* Success; impersonation count decreased but still not zero */
1165 return TRUE;
1166 }
1167 }
1168
1169 /* Impersonation has been totally removed, revert to ourselves */
1170 Status = NtSetInformationThread(NtCurrentThread(),
1171 ThreadImpersonationToken,
1172 &ImpersonationToken,
1173 sizeof(HANDLE));
1174
1175 /* Return TRUE or FALSE */
1176 return NT_SUCCESS(Status);
1177 }
1178
1179 /*++
1180 * @name CsrSetBackgroundPriority
1181 * @implemented NT4
1182 *
1183 * The CsrSetBackgroundPriority routine sets the priority for the given CSR
1184 * Process as a Background priority.
1185 *
1186 * @param CsrProcess
1187 * Pointer to the CSR Process whose priority will be modified.
1188 *
1189 * @return None.
1190 *
1191 * @remarks None.
1192 *
1193 *--*/
1194 VOID
1195 NTAPI
1196 CsrSetBackgroundPriority(IN PCSR_PROCESS CsrProcess)
1197 {
1198 PROCESS_PRIORITY_CLASS PriorityClass;
1199
1200 /* Set the Foreground bit off */
1201 PriorityClass.Foreground = FALSE;
1202
1203 /* Set the new Priority */
1204 NtSetInformationProcess(CsrProcess->ProcessHandle,
1205 ProcessPriorityClass,
1206 &PriorityClass,
1207 sizeof(PriorityClass));
1208 }
1209
1210 /*++
1211 * @name CsrSetForegroundPriority
1212 * @implemented NT4
1213 *
1214 * The CsrSetForegroundPriority routine sets the priority for the given CSR
1215 * Process as a Foreground priority.
1216 *
1217 * @param CsrProcess
1218 * Pointer to the CSR Process whose priority will be modified.
1219 *
1220 * @return None.
1221 *
1222 * @remarks None.
1223 *
1224 *--*/
1225 VOID
1226 NTAPI
1227 CsrSetForegroundPriority(IN PCSR_PROCESS CsrProcess)
1228 {
1229 PROCESS_PRIORITY_CLASS PriorityClass;
1230
1231 /* Set the Foreground bit on */
1232 PriorityClass.Foreground = TRUE;
1233
1234 /* Set the new Priority */
1235 NtSetInformationProcess(CsrProcess->ProcessHandle,
1236 ProcessPriorityClass,
1237 &PriorityClass,
1238 sizeof(PriorityClass));
1239 }
1240
1241 /*++
1242 * @name CsrShutdownProcesses
1243 * @implemented NT4
1244 *
1245 * The CsrShutdownProcesses routine shuts down every CSR Process possible
1246 * and calls each Server DLL's shutdown notification.
1247 *
1248 * @param CallerLuid
1249 * Pointer to the LUID of the CSR Process that is ordering the
1250 * shutdown.
1251 *
1252 * @param Flags
1253 * Flags to send to the shutdown notification routine.
1254 *
1255 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL otherwise.
1256 *
1257 * @remarks None.
1258 *
1259 *--*/
1260 NTSTATUS
1261 NTAPI
1262 CsrShutdownProcesses(IN PLUID CallerLuid,
1263 IN ULONG Flags)
1264 {
1265 PLIST_ENTRY NextEntry;
1266 PCSR_PROCESS CsrProcess;
1267 NTSTATUS Status;
1268 BOOLEAN FirstTry;
1269 ULONG i;
1270 PCSR_SERVER_DLL ServerDll;
1271 ULONG Result = 0; /* Intentionally invalid enumeratee to silence compiler warning */
1272
1273 /* Acquire process lock */
1274 CsrAcquireProcessLock();
1275
1276 /* Add shutdown flag */
1277 CsrRootProcess->ShutdownFlags |= CsrShutdownSystem;
1278
1279 /* Get the list pointers */
1280 NextEntry = CsrRootProcess->ListLink.Flink;
1281 while (NextEntry != &CsrRootProcess->ListLink)
1282 {
1283 /* Get the Process */
1284 CsrProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink);
1285
1286 /* Move to the next entry */
1287 NextEntry = NextEntry->Flink;
1288
1289 /* Remove the skip flag, set shutdown flags to 0 */
1290 CsrProcess->Flags &= ~CsrProcessSkipShutdown;
1291 CsrProcess->ShutdownFlags = 0;
1292 }
1293
1294 /* Set shudown Priority */
1295 CsrSetToShutdownPriority();
1296
1297 /* Start looping */
1298 while (TRUE)
1299 {
1300 /* Find the next process to shutdown */
1301 CsrProcess = FindProcessForShutdown(CallerLuid);
1302 if (!CsrProcess) break;
1303
1304 /* Increase reference to process */
1305 CsrLockedReferenceProcess(CsrProcess);
1306
1307 FirstTry = TRUE;
1308 while (TRUE)
1309 {
1310 /* Loop all the servers */
1311 for (i = 0; i < CSR_SERVER_DLL_MAX; i++)
1312 {
1313 /* Get the current server */
1314 ServerDll = CsrLoadedServerDll[i];
1315
1316 /* Check if it's valid and if it has a Shutdown Process Callback */
1317 if (ServerDll && ServerDll->ShutdownProcessCallback)
1318 {
1319 /* Release the lock, make the callback, and acquire it back */
1320 CsrReleaseProcessLock();
1321 Result = ServerDll->ShutdownProcessCallback(CsrProcess,
1322 Flags,
1323 FirstTry);
1324 CsrAcquireProcessLock();
1325
1326 /* Check the result */
1327 if (Result == CsrShutdownCsrProcess)
1328 {
1329 /* The callback unlocked the process */
1330 break;
1331 }
1332 else if (Result == CsrShutdownCancelled)
1333 {
1334 /* Check if this was a forced shutdown */
1335 if (Flags & EWX_FORCE)
1336 {
1337 DPRINT1("Process %x cancelled forced shutdown (Dll = %d)\n",
1338 CsrProcess->ClientId.UniqueProcess, i);
1339 DbgBreakPoint();
1340 }
1341
1342 /* Shutdown was cancelled, unlock and exit */
1343 CsrReleaseProcessLock();
1344 Status = STATUS_CANCELLED;
1345 goto Quickie;
1346 }
1347 }
1348 }
1349
1350 /* No matches during the first try, so loop again */
1351 if ((FirstTry) && (Result == CsrShutdownNonCsrProcess))
1352 {
1353 FirstTry = FALSE;
1354 continue;
1355 }
1356
1357 /* Second try, break out */
1358 break;
1359 }
1360
1361 /* We've reached the final loop here, so dereference */
1362 if (i == CSR_SERVER_DLL_MAX) CsrLockedDereferenceProcess(CsrProcess);
1363 }
1364
1365 /* Success path */
1366 CsrReleaseProcessLock();
1367 Status = STATUS_SUCCESS;
1368
1369 Quickie:
1370 /* Return to normal priority */
1371 CsrSetToNormalPriority();
1372
1373 return Status;
1374 }
1375
1376 /* HACK: Temporary hack. This is really "CsrShutdownProcesses", mostly. Used by winsrv */
1377 #if 0
1378 NTSTATUS
1379 WINAPI
1380 CsrEnumProcesses(IN CSRSS_ENUM_PROCESS_PROC EnumProc,
1381 IN PVOID Context)
1382 {
1383 PVOID* RealContext = (PVOID*)Context;
1384 PLUID CallerLuid = RealContext[0];
1385 PCSR_PROCESS CsrProcess = NULL;
1386 NTSTATUS Status = STATUS_UNSUCCESSFUL;
1387 BOOLEAN FirstTry;
1388 PLIST_ENTRY NextEntry;
1389 ULONG Result = 0;
1390
1391 /* Acquire process lock */
1392 CsrAcquireProcessLock();
1393
1394 /* Get the list pointers */
1395 NextEntry = CsrRootProcess->ListLink.Flink;
1396 while (NextEntry != &CsrRootProcess->ListLink)
1397 {
1398 /* Get the Process */
1399 CsrProcess = CONTAINING_RECORD(NextEntry, CSR_PROCESS, ListLink);
1400
1401 /* Move to the next entry */
1402 NextEntry = NextEntry->Flink;
1403
1404 /* Remove the skip flag, set shutdown flags to 0 */
1405 CsrProcess->Flags &= ~CsrProcessSkipShutdown;
1406 CsrProcess->ShutdownFlags = 0;
1407 }
1408
1409 /* Set shudown Priority */
1410 CsrSetToShutdownPriority();
1411
1412 /* Loop all processes */
1413 //DPRINT1("Enumerating for LUID: %lx %lx\n", CallerLuid->HighPart, CallerLuid->LowPart);
1414
1415 /* Start looping */
1416 while (TRUE)
1417 {
1418 /* Find the next process to shutdown */
1419 FirstTry = TRUE;
1420 if (!(CsrProcess = FindProcessForShutdown(CallerLuid)))
1421 {
1422 /* Done, quit */
1423 CsrReleaseProcessLock();
1424 Status = STATUS_SUCCESS;
1425 goto Quickie;
1426 }
1427
1428 LoopAgain:
1429 /* Release the lock, make the callback, and acquire it back */
1430 //DPRINT1("Found process: %lx\n", CsrProcess->ClientId.UniqueProcess);
1431 CsrReleaseProcessLock();
1432 Result = (ULONG)EnumProc(CsrProcess, (PVOID)((ULONG_PTR)Context | FirstTry));
1433 CsrAcquireProcessLock();
1434
1435 /* Check the result */
1436 //DPRINT1("Result: %d\n", Result);
1437 if (Result == CsrShutdownCsrProcess)
1438 {
1439 /* The callback unlocked the process */
1440 break;
1441 }
1442 else if (Result == CsrShutdownNonCsrProcess)
1443 {
1444 /* A non-CSR process, the callback didn't touch it */
1445 //continue;
1446 }
1447 else if (Result == CsrShutdownCancelled)
1448 {
1449 /* Shutdown was cancelled, unlock and exit */
1450 CsrReleaseProcessLock();
1451 Status = STATUS_CANCELLED;
1452 goto Quickie;
1453 }
1454
1455 /* No matches during the first try, so loop again */
1456 if (FirstTry && Result == CsrShutdownNonCsrProcess)
1457 {
1458 FirstTry = FALSE;
1459 goto LoopAgain;
1460 }
1461 }
1462
1463 Quickie:
1464 /* Return to normal priority */
1465 CsrSetToNormalPriority();
1466 return Status;
1467 }
1468 #endif
1469
1470 /*++
1471 * @name CsrUnlockProcess
1472 * @implemented NT4
1473 *
1474 * The CsrUnlockProcess undoes a previous CsrLockProcessByClientId operation.
1475 *
1476 * @param CsrProcess
1477 * Pointer to a previously locked CSR Process.
1478 *
1479 * @return STATUS_SUCCESS.
1480 *
1481 * @remarks This routine must be called with the Process Lock held.
1482 *
1483 *--*/
1484 NTSTATUS
1485 NTAPI
1486 CsrUnlockProcess(IN PCSR_PROCESS CsrProcess)
1487 {
1488 /* Dereference the process */
1489 CsrLockedDereferenceProcess(CsrProcess);
1490
1491 /* Release the lock and return */
1492 CsrReleaseProcessLock();
1493 return STATUS_SUCCESS;
1494 }
1495
1496 /* EOF */