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