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