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