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