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