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