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