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