[CSRSS]: Split off CSRSS into a more Windows-friendly model. CSRSS.EXE is simply...
[reactos.git] / reactos / subsystems / win32 / csrss / csrsrv / api / process.c
1 /*
2 * reactos/subsys/csrss/api/process.c
3 *
4 * "\windows\ApiPort" port process management functions
5 *
6 * ReactOS Operating System
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <srv.h>
12
13 #define NDEBUG
14 #include <debug.h>
15
16 #define LOCK RtlEnterCriticalSection(&ProcessDataLock)
17 #define UNLOCK RtlLeaveCriticalSection(&ProcessDataLock)
18
19 /* GLOBALS *******************************************************************/
20
21 static ULONG NrProcess;
22 static PCSRSS_PROCESS_DATA ProcessData[256];
23 RTL_CRITICAL_SECTION ProcessDataLock;
24
25 /* FUNCTIONS *****************************************************************/
26
27 #define CsrHeap RtlGetProcessHeap()
28
29 #define CsrHashThread(t) \
30 (HandleToUlong(t)&(256 - 1))
31
32 LIST_ENTRY CsrThreadHashTable[256];
33 PCSRSS_PROCESS_DATA CsrRootProcess;
34
35 PCSR_THREAD
36 NTAPI
37 CsrAllocateThread(IN PCSRSS_PROCESS_DATA CsrProcess)
38 {
39 PCSR_THREAD CsrThread;
40
41 /* Allocate the structure */
42 CsrThread = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, sizeof(CSR_THREAD));
43 if (!CsrThread) return(NULL);
44
45 /* Reference the Thread and Process */
46 CsrThread->ReferenceCount++;
47 // CsrProcess->ReferenceCount++;
48
49 /* Set the Parent Process */
50 CsrThread->Process = CsrProcess;
51
52 /* Return Thread */
53 return CsrThread;
54 }
55
56 PCSR_THREAD
57 NTAPI
58 CsrLocateThreadByClientId(OUT PCSRSS_PROCESS_DATA *Process OPTIONAL,
59 IN PCLIENT_ID ClientId)
60 {
61 ULONG i;
62 PLIST_ENTRY ListHead, NextEntry;
63 PCSR_THREAD FoundThread;
64
65 /* Hash the Thread */
66 i = CsrHashThread(ClientId->UniqueThread);
67
68 /* Set the list pointers */
69 ListHead = &CsrThreadHashTable[i];
70 NextEntry = ListHead->Flink;
71
72 /* Star the loop */
73 while (NextEntry != ListHead)
74 {
75 /* Get the thread */
76 FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks);
77
78 /* Compare the CID */
79 if (FoundThread->ClientId.UniqueThread == ClientId->UniqueThread)
80 {
81 /* Match found, return the process */
82 *Process = FoundThread->Process;
83
84 /* Return thread too */
85 // DPRINT1("Found: %p %p\n", FoundThread, FoundThread->Process);
86 return FoundThread;
87 }
88
89 /* Next */
90 NextEntry = NextEntry->Flink;
91 }
92
93 /* Nothing found */
94 return NULL;
95 }
96
97 PCSR_THREAD
98 NTAPI
99 CsrLocateThreadInProcess(IN PCSRSS_PROCESS_DATA CsrProcess OPTIONAL,
100 IN PCLIENT_ID Cid)
101 {
102 PLIST_ENTRY ListHead, NextEntry;
103 PCSR_THREAD FoundThread = NULL;
104
105 /* Use the Root Process if none was specified */
106 if (!CsrProcess) CsrProcess = CsrRootProcess;
107
108 /* Save the List pointers */
109 // DPRINT1("Searching in: %p %d\n", CsrProcess, CsrProcess->ThreadCount);
110 ListHead = &CsrProcess->ThreadList;
111 NextEntry = ListHead->Flink;
112
113 /* Start the Loop */
114 while (NextEntry != ListHead)
115 {
116 /* Get Thread Entry */
117 FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
118
119 /* Check for TID Match */
120 if (FoundThread->ClientId.UniqueThread == Cid->UniqueThread) break;
121
122 /* Next entry */
123 NextEntry = NextEntry->Flink;
124 }
125
126 /* Return what we found */
127 // DPRINT1("Found: %p\n", FoundThread);
128 return FoundThread;
129 }
130
131 VOID
132 NTAPI
133 CsrInsertThread(IN PCSRSS_PROCESS_DATA Process,
134 IN PCSR_THREAD Thread)
135 {
136 ULONG i;
137
138 /* Insert it into the Regular List */
139 InsertTailList(&Process->ThreadList, &Thread->Link);
140
141 /* Increase Thread Count */
142 Process->ThreadCount++;
143
144 /* Hash the Thread */
145 i = CsrHashThread(Thread->ClientId.UniqueThread);
146 // DPRINT1("TID %lx HASH: %lx\n", Thread->ClientId.UniqueThread, i);
147
148 /* Insert it there too */
149 InsertHeadList(&CsrThreadHashTable[i], &Thread->HashLinks);
150 }
151
152
153 #define CsrAcquireProcessLock() LOCK
154 #define CsrReleaseProcessLock() UNLOCK
155
156 VOID
157 NTAPI
158 CsrDeallocateThread(IN PCSR_THREAD CsrThread)
159 {
160 /* Free the process object from the heap */
161 RtlFreeHeap(CsrHeap, 0, CsrThread);
162 }
163
164 VOID
165 NTAPI
166 CsrRemoveThread(IN PCSR_THREAD CsrThread)
167 {
168 /* Remove it from the List */
169 RemoveEntryList(&CsrThread->Link);
170
171 /* Decreate the thread count of the process */
172 CsrThread->Process->ThreadCount--;
173
174 /* Remove it from the Hash List as well */
175 if (CsrThread->HashLinks.Flink) RemoveEntryList(&CsrThread->HashLinks);
176
177 /* Check if this is the last Thread */
178 if (!CsrThread->Process->ThreadCount)
179 {
180 /* Check if it's not already been marked for deletion */
181 if (!(CsrThread->Process->Flags & CsrProcessLastThreadTerminated))
182 {
183 /* Let everyone know this process is about to lose the thread */
184 //CsrThread->Process->Flags |= CsrProcessLastThreadTerminated;
185
186 /* Reference the Process */
187 //CsrLockedDereferenceProcess(CsrThread->Process);
188 }
189 }
190
191 /* Mark the thread for deletion */
192 CsrThread->Flags |= CsrThreadInTermination;
193 }
194
195 VOID
196 NTAPI
197 CsrThreadRefcountZero(IN PCSR_THREAD CsrThread)
198 {
199 /* Remove this thread */
200 CsrRemoveThread(CsrThread);
201
202 /* Release the Process Lock */
203 //CsrReleaseProcessLock();
204
205 /* Close the NT Thread Handle */
206 if (CsrThread->ThreadHandle) NtClose(CsrThread->ThreadHandle);
207
208 /* De-allocate the CSR Thread Object */
209 CsrDeallocateThread(CsrThread);
210
211 /* Remove a reference from the process */
212 //CsrDereferenceProcess(CsrProcess);
213 }
214
215 NTSTATUS
216 NTAPI
217 CsrCreateThreadData(IN PCSRSS_PROCESS_DATA CsrProcess,
218 IN HANDLE hThread,
219 IN PCLIENT_ID ClientId)
220 {
221 NTSTATUS Status;
222 PCSR_THREAD CsrThread;
223 //PCSRSS_PROCESS_DATA CurrentProcess;
224 PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
225 CLIENT_ID CurrentCid;
226 KERNEL_USER_TIMES KernelTimes;
227
228 // DPRINT1("CSRSRV: %s called\n", __FUNCTION__);
229
230 /* Get the current thread and CID */
231 CurrentCid = CurrentThread->ClientId;
232 // DPRINT1("CALLER PID/TID: %lx/%lx\n", CurrentCid.UniqueProcess, CurrentCid.UniqueThread);
233
234 /* Acquire the Process Lock */
235 CsrAcquireProcessLock();
236 #if 0
237 /* Get the current Process and make sure the Thread is valid with this CID */
238 CurrentThread = CsrLocateThreadByClientId(&CurrentProcess,
239 &CurrentCid);
240
241 /* Something is wrong if we get an empty thread back */
242 if (!CurrentThread)
243 {
244 DPRINT1("CSRSRV:%s: invalid thread!\n", __FUNCTION__);
245 CsrReleaseProcessLock();
246 return STATUS_THREAD_IS_TERMINATING;
247 }
248 #endif
249 /* Get the Thread Create Time */
250 Status = NtQueryInformationThread(hThread,
251 ThreadTimes,
252 (PVOID)&KernelTimes,
253 sizeof(KernelTimes),
254 NULL);
255
256 /* Allocate a CSR Thread Structure */
257 if (!(CsrThread = CsrAllocateThread(CsrProcess)))
258 {
259 DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__);
260 CsrReleaseProcessLock();
261 return STATUS_NO_MEMORY;
262 }
263
264 /* Save the data we have */
265 CsrThread->CreateTime = KernelTimes.CreateTime;
266 CsrThread->ClientId = *ClientId;
267 CsrThread->ThreadHandle = hThread;
268 CsrThread->Flags = 0;
269
270 /* Insert the Thread into the Process */
271 CsrInsertThread(CsrProcess, CsrThread);
272
273 /* Release the lock and return */
274 CsrReleaseProcessLock();
275 return STATUS_SUCCESS;
276 }
277
278 PCSR_THREAD
279 NTAPI
280 CsrAddStaticServerThread(IN HANDLE hThread,
281 IN PCLIENT_ID ClientId,
282 IN ULONG ThreadFlags)
283 {
284 PCSR_THREAD CsrThread;
285
286 /* Get the Lock */
287 CsrAcquireProcessLock();
288
289 /* Allocate the Server Thread */
290 if ((CsrThread = CsrAllocateThread(CsrRootProcess)))
291 {
292 /* Setup the Object */
293 // DPRINT1("New CSR thread created: %lx PID/TID: %lx/%lx\n", CsrThread, ClientId->UniqueProcess, ClientId->UniqueThread);
294 CsrThread->ThreadHandle = hThread;
295 CsrThread->ClientId = *ClientId;
296 CsrThread->Flags = ThreadFlags;
297
298 /* Insert it into the Thread List */
299 InsertTailList(&CsrRootProcess->ThreadList, &CsrThread->Link);
300
301 /* Increment the thread count */
302 CsrRootProcess->ThreadCount++;
303 }
304
305 /* Release the Process Lock and return */
306 CsrReleaseProcessLock();
307 return CsrThread;
308 }
309
310 VOID WINAPI CsrInitProcessData(VOID)
311 {
312 ULONG i;
313 RtlZeroMemory (ProcessData, sizeof ProcessData);
314 NrProcess = sizeof ProcessData / sizeof ProcessData[0];
315 RtlInitializeCriticalSection( &ProcessDataLock );
316
317 CsrRootProcess = CsrCreateProcessData(NtCurrentTeb()->ClientId.UniqueProcess);
318
319 /* Initialize the Thread Hash List */
320 for (i = 0; i < 256; i++) InitializeListHead(&CsrThreadHashTable[i]);
321 }
322
323 PCSRSS_PROCESS_DATA WINAPI CsrGetProcessData(HANDLE ProcessId)
324 {
325 ULONG hash;
326 PCSRSS_PROCESS_DATA pProcessData;
327
328 hash = ((ULONG_PTR)ProcessId >> 2) % (sizeof(ProcessData) / sizeof(*ProcessData));
329
330 LOCK;
331
332 pProcessData = ProcessData[hash];
333
334 while (pProcessData && pProcessData->ProcessId != ProcessId)
335 {
336 pProcessData = pProcessData->next;
337 }
338 UNLOCK;
339 return pProcessData;
340 }
341
342 PCSRSS_PROCESS_DATA WINAPI CsrCreateProcessData(HANDLE ProcessId)
343 {
344 ULONG hash;
345 PCSRSS_PROCESS_DATA pProcessData;
346 OBJECT_ATTRIBUTES ObjectAttributes;
347 CLIENT_ID ClientId;
348 NTSTATUS Status;
349
350 hash = ((ULONG_PTR)ProcessId >> 2) % (sizeof(ProcessData) / sizeof(*ProcessData));
351
352 LOCK;
353
354 pProcessData = ProcessData[hash];
355
356 while (pProcessData && pProcessData->ProcessId != ProcessId)
357 {
358 pProcessData = pProcessData->next;
359 }
360 if (pProcessData == NULL)
361 {
362 pProcessData = RtlAllocateHeap(CsrssApiHeap,
363 HEAP_ZERO_MEMORY,
364 sizeof(CSRSS_PROCESS_DATA));
365 if (pProcessData)
366 {
367 pProcessData->ProcessId = ProcessId;
368 pProcessData->next = ProcessData[hash];
369 ProcessData[hash] = pProcessData;
370
371 ClientId.UniqueThread = NULL;
372 ClientId.UniqueProcess = pProcessData->ProcessId;
373 InitializeObjectAttributes(&ObjectAttributes,
374 NULL,
375 0,
376 NULL,
377 NULL);
378
379 /* using OpenProcess is not optimal due to HANDLE vs. DWORD PIDs... */
380 Status = NtOpenProcess(&pProcessData->Process,
381 PROCESS_ALL_ACCESS,
382 &ObjectAttributes,
383 &ClientId);
384 if (!NT_SUCCESS(Status))
385 {
386 ProcessData[hash] = pProcessData->next;
387 RtlFreeHeap(CsrssApiHeap, 0, pProcessData);
388 pProcessData = NULL;
389 }
390 else
391 {
392 RtlInitializeCriticalSection(&pProcessData->HandleTableLock);
393 }
394 }
395 }
396 else
397 {
398 DPRINT1("Process data for pid %d already exist\n", ProcessId);
399 }
400 UNLOCK;
401 if (pProcessData == NULL)
402 {
403 DPRINT1("CsrCreateProcessData() failed\n");
404 }
405 else
406 {
407 pProcessData->Terminated = FALSE;
408
409 /* Set default shutdown parameters */
410 pProcessData->ShutdownLevel = 0x280;
411 pProcessData->ShutdownFlags = 0;
412 }
413
414 pProcessData->ThreadCount = 0;
415 InitializeListHead(&pProcessData->ThreadList);
416 return pProcessData;
417 }
418
419 NTSTATUS WINAPI CsrFreeProcessData(HANDLE Pid)
420 {
421 ULONG hash;
422 UINT c;
423 PCSRSS_PROCESS_DATA pProcessData, *pPrevLink;
424 HANDLE Process;
425
426 hash = ((ULONG_PTR)Pid >> 2) % (sizeof(ProcessData) / sizeof(*ProcessData));
427 pPrevLink = &ProcessData[hash];
428
429 LOCK;
430
431 while ((pProcessData = *pPrevLink) && pProcessData->ProcessId != Pid)
432 {
433 pPrevLink = &pProcessData->next;
434 }
435
436 if (pProcessData)
437 {
438 DPRINT("CsrFreeProcessData pid: %d\n", Pid);
439 Process = pProcessData->Process;
440 if (pProcessData->HandleTable)
441 {
442 for (c = 0; c < pProcessData->HandleTableSize; c++)
443 {
444 if (pProcessData->HandleTable[c].Object)
445 {
446 CsrReleaseObjectByPointer(pProcessData->HandleTable[c].Object);
447 }
448 }
449 RtlFreeHeap(CsrssApiHeap, 0, pProcessData->HandleTable);
450 }
451 RtlDeleteCriticalSection(&pProcessData->HandleTableLock);
452 if (pProcessData->Console)
453 {
454 RemoveEntryList(&pProcessData->ProcessEntry);
455 CsrReleaseObjectByPointer((Object_t *) pProcessData->Console);
456 }
457 if (pProcessData->CsrSectionViewBase)
458 {
459 NtUnmapViewOfSection(NtCurrentProcess(), pProcessData->CsrSectionViewBase);
460 }
461 if (pProcessData->ServerCommunicationPort)
462 {
463 NtClose(pProcessData->ServerCommunicationPort);
464 }
465 *pPrevLink = pProcessData->next;
466
467 RtlFreeHeap(CsrssApiHeap, 0, pProcessData);
468 UNLOCK;
469 if (Process)
470 {
471 NtClose(Process);
472 }
473 return STATUS_SUCCESS;
474 }
475
476 UNLOCK;
477 return STATUS_INVALID_PARAMETER;
478 }
479
480 VOID
481 NTAPI
482 CsrSetToNormalPriority(VOID)
483 {
484 KPRIORITY BasePriority = (8 + 1) + 4;
485
486 /* Set the Priority */
487 NtSetInformationProcess(NtCurrentProcess(),
488 ProcessBasePriority,
489 &BasePriority,
490 sizeof(KPRIORITY));
491 }
492
493 VOID
494 NTAPI
495 CsrSetToShutdownPriority(VOID)
496 {
497 KPRIORITY SetBasePriority = (8 + 1) + 6;
498 BOOLEAN Old;
499
500 /* Get the shutdown privilege */
501 if (NT_SUCCESS(RtlAdjustPrivilege(SE_SHUTDOWN_PRIVILEGE,
502 TRUE,
503 FALSE,
504 &Old)))
505 {
506 /* Set the Priority */
507 NtSetInformationProcess(NtCurrentProcess(),
508 ProcessBasePriority,
509 &SetBasePriority,
510 sizeof(KPRIORITY));
511 }
512 }
513
514 NTSTATUS
515 NTAPI
516 CsrGetProcessLuid(HANDLE hProcess OPTIONAL,
517 PLUID Luid)
518 {
519 HANDLE hToken = NULL;
520 NTSTATUS Status;
521 ULONG Length;
522 PTOKEN_STATISTICS TokenStats;
523
524 /* Check if we have a handle to a CSR Process */
525 if (!hProcess)
526 {
527 /* We don't, so try opening the Thread's Token */
528 Status = NtOpenThreadToken(NtCurrentThread(),
529 TOKEN_QUERY,
530 FALSE,
531 &hToken);
532
533 /* Check for success */
534 if (!NT_SUCCESS(Status))
535 {
536 /* If we got some other failure, then return and quit */
537 if (Status != STATUS_NO_TOKEN) return Status;
538
539 /* We don't have a Thread Token, use a Process Token */
540 hProcess = NtCurrentProcess();
541 hToken = NULL;
542 }
543 }
544
545 /* Check if we have a token by now */
546 if (!hToken)
547 {
548 /* No token yet, so open the Process Token */
549 Status = NtOpenProcessToken(hProcess,
550 TOKEN_QUERY,
551 &hToken);
552 if (!NT_SUCCESS(Status))
553 {
554 /* Still no token, return the error */
555 return Status;
556 }
557 }
558
559 /* Now get the size we'll need for the Token Information */
560 Status = NtQueryInformationToken(hToken,
561 TokenStatistics,
562 NULL,
563 0,
564 &Length);
565
566 /* Allocate memory for the Token Info */
567 if (!(TokenStats = RtlAllocateHeap(CsrHeap, 0, Length)))
568 {
569 /* Fail and close the token */
570 NtClose(hToken);
571 return STATUS_NO_MEMORY;
572 }
573
574 /* Now query the information */
575 Status = NtQueryInformationToken(hToken,
576 TokenStatistics,
577 TokenStats,
578 Length,
579 &Length);
580
581 /* Close the handle */
582 NtClose(hToken);
583
584 /* Check for success */
585 if (NT_SUCCESS(Status))
586 {
587 /* Return the LUID */
588 *Luid = TokenStats->AuthenticationId;
589 }
590
591 /* Free the query information */
592 RtlFreeHeap(CsrHeap, 0, TokenStats);
593
594 /* Return the Status */
595 return Status;
596 }
597
598 SECURITY_QUALITY_OF_SERVICE CsrSecurityQos =
599 {
600 sizeof(SECURITY_QUALITY_OF_SERVICE),
601 SecurityImpersonation,
602 SECURITY_STATIC_TRACKING,
603 FALSE
604 };
605
606 BOOLEAN
607 NTAPI
608 CsrImpersonateClient(IN PCSR_THREAD CsrThread)
609 {
610 NTSTATUS Status;
611 PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
612
613 /* Use the current thread if none given */
614 if (!CsrThread) CsrThread = CurrentThread;
615
616 /* Still no thread, something is wrong */
617 if (!CsrThread)
618 {
619 /* Failure */
620 return FALSE;
621 }
622
623 /* Make the call */
624 Status = NtImpersonateThread(NtCurrentThread(),
625 CsrThread->ThreadHandle,
626 &CsrSecurityQos);
627
628 if (!NT_SUCCESS(Status))
629 {
630 /* Failure */
631 return FALSE;
632 }
633
634 /* Increase the impersonation count for the current thread */
635 if (CurrentThread) ++CurrentThread->ImpersonationCount;
636
637 /* Return Success */
638 return TRUE;
639 }
640
641 BOOLEAN
642 NTAPI
643 CsrRevertToSelf(VOID)
644 {
645 NTSTATUS Status;
646 PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
647 HANDLE ImpersonationToken = NULL;
648
649 /* Check if we have a Current Thread */
650 if (CurrentThread)
651 {
652 /* Make sure impersonation is on */
653 if (!CurrentThread->ImpersonationCount)
654 {
655 return FALSE;
656 }
657 else if (--CurrentThread->ImpersonationCount > 0)
658 {
659 /* Success; impersonation count decreased but still not zero */
660 return TRUE;
661 }
662 }
663
664 /* Impersonation has been totally removed, revert to ourselves */
665 Status = NtSetInformationThread(NtCurrentThread(),
666 ThreadImpersonationToken,
667 &ImpersonationToken,
668 sizeof(HANDLE));
669
670 /* Return TRUE or FALSE */
671 return NT_SUCCESS(Status);
672 }
673
674 PCSRSS_PROCESS_DATA
675 NTAPI
676 FindProcessForShutdown(IN PLUID CallerLuid)
677 {
678 ULONG Hash;
679 PCSRSS_PROCESS_DATA CsrProcess, ReturnCsrProcess = NULL;
680 NTSTATUS Status;
681 ULONG Level = 0;
682 LUID ProcessLuid;
683 LUID SystemLuid = SYSTEM_LUID;
684 BOOLEAN IsSystemLuid = FALSE, IsOurLuid = FALSE;
685
686 for (Hash = 0; Hash < (sizeof(ProcessData) / sizeof(*ProcessData)); Hash++)
687 {
688 /* Get this process hash bucket */
689 CsrProcess = ProcessData[Hash];
690 while (CsrProcess)
691 {
692 /* Skip this process if it's already been processed*/
693 if (CsrProcess->Flags & CsrProcessSkipShutdown) goto Next;
694
695 /* Get the LUID of this Process */
696 Status = CsrGetProcessLuid(CsrProcess->Process, &ProcessLuid);
697
698 /* Check if we didn't get access to the LUID */
699 if (Status == STATUS_ACCESS_DENIED)
700 {
701 /* FIXME:Check if we have any threads */
702 }
703
704 if (!NT_SUCCESS(Status))
705 {
706 /* We didn't have access, so skip it */
707 CsrProcess->Flags |= CsrProcessSkipShutdown;
708 goto Next;
709 }
710
711 /* Check if this is the System LUID */
712 if ((IsSystemLuid = RtlEqualLuid(&ProcessLuid, &SystemLuid)))
713 {
714 /* Mark this process */
715 CsrProcess->ShutdownFlags |= CsrShutdownSystem;
716 }
717 else if (!(IsOurLuid = RtlEqualLuid(&ProcessLuid, CallerLuid)))
718 {
719 /* Our LUID doesn't match with the caller's */
720 CsrProcess->ShutdownFlags |= CsrShutdownOther;
721 }
722
723 /* Check if we're past the previous level */
724 if (CsrProcess->ShutdownLevel > Level)
725 {
726 /* Update the level */
727 Level = CsrProcess->ShutdownLevel;
728
729 /* Set the final process */
730 ReturnCsrProcess = CsrProcess;
731 }
732 Next:
733 /* Next process */
734 CsrProcess = CsrProcess->next;
735 }
736 }
737
738 /* Check if we found a process */
739 if (ReturnCsrProcess)
740 {
741 /* Skip this one next time */
742 ReturnCsrProcess->Flags |= CsrProcessSkipShutdown;
743 }
744
745 return ReturnCsrProcess;
746 }
747
748 /* This is really "CsrShutdownProcess", mostly */
749 NTSTATUS
750 WINAPI
751 CsrEnumProcesses(IN CSRSS_ENUM_PROCESS_PROC EnumProc,
752 IN PVOID Context)
753 {
754 PVOID* RealContext = (PVOID*)Context;
755 PLUID CallerLuid = RealContext[0];
756 PCSRSS_PROCESS_DATA CsrProcess = NULL;
757 NTSTATUS Status = STATUS_UNSUCCESSFUL;
758 BOOLEAN FirstTry;
759 ULONG Result = 0;
760 ULONG Hash;
761
762 /* Acquire process lock */
763 CsrAcquireProcessLock();
764
765 /* Start the loop */
766 for (Hash = 0; Hash < (sizeof(ProcessData) / sizeof(*ProcessData)); Hash++)
767 {
768 /* Get the Process */
769 CsrProcess = ProcessData[Hash];
770 while (CsrProcess)
771 {
772 /* Remove the skip flag, set shutdown flags to 0*/
773 CsrProcess->Flags &= ~CsrProcessSkipShutdown;
774 CsrProcess->ShutdownFlags = 0;
775
776 /* Move to the next */
777 CsrProcess = CsrProcess->next;
778 }
779 }
780
781 /* Set shudown Priority */
782 CsrSetToShutdownPriority();
783
784 /* Loop all processes */
785 DPRINT1("Enumerating for LUID: %lx %lx\n", CallerLuid->HighPart, CallerLuid->LowPart);
786
787 /* Start looping */
788 while (TRUE)
789 {
790 /* Find the next process to shutdown */
791 FirstTry = TRUE;
792 if (!(CsrProcess = FindProcessForShutdown(CallerLuid)))
793 {
794 /* Done, quit */
795 CsrReleaseProcessLock();
796 Status = STATUS_SUCCESS;
797 goto Quickie;
798 }
799
800 LoopAgain:
801 /* Release the lock, make the callback, and acquire it back */
802 DPRINT1("Found process: %lx\n", CsrProcess->ProcessId);
803 CsrReleaseProcessLock();
804 Result = (ULONG)EnumProc(CsrProcess, (PVOID)((ULONG_PTR)Context | FirstTry));
805 CsrAcquireProcessLock();
806
807 /* Check the result */
808 DPRINT1("Result: %d\n", Result);
809 if (Result == CsrShutdownCsrProcess)
810 {
811 /* The callback unlocked the process */
812 break;
813 }
814 else if (Result == CsrShutdownNonCsrProcess)
815 {
816 /* A non-CSR process, the callback didn't touch it */
817 //continue;
818 }
819 else if (Result == CsrShutdownCancelled)
820 {
821 /* Shutdown was cancelled, unlock and exit */
822 CsrReleaseProcessLock();
823 Status = STATUS_CANCELLED;
824 goto Quickie;
825 }
826
827 /* No matches during the first try, so loop again */
828 if (FirstTry && Result == CsrShutdownNonCsrProcess)
829 {
830 FirstTry = FALSE;
831 goto LoopAgain;
832 }
833 }
834
835 Quickie:
836 /* Return to normal priority */
837 CsrSetToNormalPriority();
838 return Status;
839 }
840
841 NTSTATUS
842 NTAPI
843 CsrLockProcessByClientId(IN HANDLE Pid,
844 OUT PCSRSS_PROCESS_DATA *CsrProcess OPTIONAL)
845 {
846 ULONG Hash;
847 PCSRSS_PROCESS_DATA CurrentProcess = NULL;
848 NTSTATUS Status = STATUS_UNSUCCESSFUL;
849
850 /* Acquire the lock */
851 CsrAcquireProcessLock();
852
853 /* Start the loop */
854 for (Hash = 0; Hash < (sizeof(ProcessData) / sizeof(*ProcessData)); Hash++)
855 {
856 /* Get the Process */
857 CurrentProcess = ProcessData[Hash];
858 while (CurrentProcess)
859 {
860 /* Check for PID match */
861 if (CurrentProcess->ProcessId == Pid)
862 {
863 /* Get out of here with success */
864 // DPRINT1("Found %p for PID %lx\n", CurrentProcess, Pid);
865 Status = STATUS_SUCCESS;
866 goto Found;
867 }
868
869 /* Move to the next */
870 CurrentProcess = CurrentProcess->next;
871 }
872 }
873
874 /* Nothing found, release the lock */
875 Found:
876 if (!CurrentProcess) CsrReleaseProcessLock();
877
878 /* Return the status and process */
879 if (CsrProcess) *CsrProcess = CurrentProcess;
880 return Status;
881 }
882
883 /**********************************************************************
884 * CSRSS API
885 *********************************************************************/
886
887 CSR_API(CsrCreateProcess)
888 {
889 PCSRSS_PROCESS_DATA NewProcessData;
890 NTSTATUS Status;
891
892 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
893 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
894
895 NewProcessData = CsrCreateProcessData(Request->Data.CreateProcessRequest.NewProcessId);
896 if (NewProcessData == NULL)
897 {
898 return(STATUS_NO_MEMORY);
899 }
900
901 if (!(Request->Data.CreateProcessRequest.Flags & (CREATE_NEW_CONSOLE|DETACHED_PROCESS)))
902 {
903 NewProcessData->ParentConsole = ProcessData->Console;
904 NewProcessData->bInheritHandles = Request->Data.CreateProcessRequest.bInheritHandles;
905 if (Request->Data.CreateProcessRequest.bInheritHandles)
906 {
907 Status = CsrDuplicateHandleTable(ProcessData, NewProcessData);
908 }
909 }
910
911 if (Request->Data.CreateProcessRequest.Flags & CREATE_NEW_PROCESS_GROUP)
912 {
913 NewProcessData->ProcessGroup = (DWORD)(ULONG_PTR)NewProcessData->ProcessId;
914 }
915 else
916 {
917 NewProcessData->ProcessGroup = ProcessData->ProcessGroup;
918 }
919
920 return(STATUS_SUCCESS);
921 }
922
923 CSR_API(CsrCreateThread)
924 {
925 PCSR_THREAD CurrentThread;
926 HANDLE ThreadHandle;
927 NTSTATUS Status;
928 PCSRSS_PROCESS_DATA CsrProcess;
929
930 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
931 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
932
933 CurrentThread = NtCurrentTeb()->CsrClientThread;
934 CsrProcess = CurrentThread->Process;
935 // DPRINT1("Current thread: %p %p\n", CurrentThread, CsrProcess);
936 // DPRINT1("Request CID: %lx %lx %lx\n",
937 // CsrProcess->ProcessId,
938 // NtCurrentTeb()->ClientId.UniqueProcess,
939 // Request->Data.CreateThreadRequest.ClientId.UniqueProcess);
940
941 if (CsrProcess->ProcessId != Request->Data.CreateThreadRequest.ClientId.UniqueProcess)
942 {
943 if (Request->Data.CreateThreadRequest.ClientId.UniqueProcess == NtCurrentTeb()->ClientId.UniqueProcess)
944 {
945 return STATUS_SUCCESS;
946 }
947
948 Status = CsrLockProcessByClientId(Request->Data.CreateThreadRequest.ClientId.UniqueProcess,
949 &CsrProcess);
950 // DPRINT1("Found matching process: %p\n", CsrProcess);
951 if (!NT_SUCCESS(Status)) return Status;
952 }
953
954 // DPRINT1("PIDs: %lx %lx\n", CurrentThread->Process->ProcessId, CsrProcess->ProcessId);
955 // DPRINT1("Thread handle is: %lx Process Handle is: %lx %lx\n",
956 // Request->Data.CreateThreadRequest.ThreadHandle,
957 // CurrentThread->Process->Process,
958 // CsrProcess->Process);
959 Status = NtDuplicateObject(CsrProcess->Process,
960 Request->Data.CreateThreadRequest.ThreadHandle,
961 NtCurrentProcess(),
962 &ThreadHandle,
963 0,
964 0,
965 DUPLICATE_SAME_ACCESS);
966 //DPRINT1("Duplicate status: %lx\n", Status);
967 if (!NT_SUCCESS(Status))
968 {
969 Status = NtDuplicateObject(CurrentThread->Process->Process,
970 Request->Data.CreateThreadRequest.ThreadHandle,
971 NtCurrentProcess(),
972 &ThreadHandle,
973 0,
974 0,
975 DUPLICATE_SAME_ACCESS);
976 // DPRINT1("Duplicate status: %lx\n", Status);
977 }
978
979 Status = STATUS_SUCCESS; // hack
980 if (NT_SUCCESS(Status))
981 {
982 Status = CsrCreateThreadData(CsrProcess,
983 ThreadHandle,
984 &Request->Data.CreateThreadRequest.ClientId);
985 // DPRINT1("Create status: %lx\n", Status);
986 }
987
988 if (CsrProcess != CurrentThread->Process) CsrReleaseProcessLock();
989
990 return Status;
991 }
992
993 CSR_API(CsrTerminateProcess)
994 {
995 PLIST_ENTRY NextEntry;
996 PCSR_THREAD Thread;
997 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
998 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
999
1000 NextEntry = ProcessData->ThreadList.Flink;
1001 while (NextEntry != &ProcessData->ThreadList)
1002 {
1003 Thread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
1004 NextEntry = NextEntry->Flink;
1005
1006 CsrThreadRefcountZero(Thread);
1007
1008 }
1009
1010
1011 ProcessData->Terminated = TRUE;
1012 return STATUS_SUCCESS;
1013 }
1014
1015 CSR_API(CsrConnectProcess)
1016 {
1017 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1018 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1019
1020 return(STATUS_SUCCESS);
1021 }
1022
1023 CSR_API(CsrGetShutdownParameters)
1024 {
1025 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1026 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1027
1028 Request->Data.GetShutdownParametersRequest.Level = ProcessData->ShutdownLevel;
1029 Request->Data.GetShutdownParametersRequest.Flags = ProcessData->ShutdownFlags;
1030
1031 return(STATUS_SUCCESS);
1032 }
1033
1034 CSR_API(CsrSetShutdownParameters)
1035 {
1036 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1037 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1038
1039 ProcessData->ShutdownLevel = Request->Data.SetShutdownParametersRequest.Level;
1040 ProcessData->ShutdownFlags = Request->Data.SetShutdownParametersRequest.Flags;
1041
1042 return(STATUS_SUCCESS);
1043 }
1044
1045 CSR_API(CsrGetInputHandle)
1046 {
1047 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1048 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1049
1050 if (ProcessData->Console)
1051 {
1052 Request->Status = CsrInsertObject(ProcessData,
1053 &Request->Data.GetInputHandleRequest.InputHandle,
1054 (Object_t *)ProcessData->Console,
1055 Request->Data.GetInputHandleRequest.Access,
1056 Request->Data.GetInputHandleRequest.Inheritable);
1057 }
1058 else
1059 {
1060 Request->Data.GetInputHandleRequest.InputHandle = INVALID_HANDLE_VALUE;
1061 Request->Status = STATUS_SUCCESS;
1062 }
1063
1064 return Request->Status;
1065 }
1066
1067 CSR_API(CsrGetOutputHandle)
1068 {
1069 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1070 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1071
1072 if (ProcessData->Console)
1073 {
1074 RtlEnterCriticalSection(&ProcessDataLock);
1075 Request->Status = CsrInsertObject(ProcessData,
1076 &Request->Data.GetOutputHandleRequest.OutputHandle,
1077 &ProcessData->Console->ActiveBuffer->Header,
1078 Request->Data.GetOutputHandleRequest.Access,
1079 Request->Data.GetOutputHandleRequest.Inheritable);
1080 RtlLeaveCriticalSection(&ProcessDataLock);
1081 }
1082 else
1083 {
1084 Request->Data.GetOutputHandleRequest.OutputHandle = INVALID_HANDLE_VALUE;
1085 Request->Status = STATUS_SUCCESS;
1086 }
1087
1088 return Request->Status;
1089 }
1090
1091 CSR_API(CsrCloseHandle)
1092 {
1093 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1094 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1095
1096 return CsrReleaseObject(ProcessData, Request->Data.CloseHandleRequest.Handle);
1097 }
1098
1099 CSR_API(CsrVerifyHandle)
1100 {
1101 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1102 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1103
1104 Request->Status = CsrVerifyObject(ProcessData, Request->Data.VerifyHandleRequest.Handle);
1105 if (!NT_SUCCESS(Request->Status))
1106 {
1107 DPRINT("CsrVerifyObject failed, status=%x\n", Request->Status);
1108 }
1109
1110 return Request->Status;
1111 }
1112
1113 CSR_API(CsrDuplicateHandle)
1114 {
1115 ULONG_PTR Index;
1116 PCSRSS_HANDLE Entry;
1117 DWORD DesiredAccess;
1118
1119 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1120 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1121
1122 Index = (ULONG_PTR)Request->Data.DuplicateHandleRequest.Handle >> 2;
1123 RtlEnterCriticalSection(&ProcessData->HandleTableLock);
1124 if (Index >= ProcessData->HandleTableSize
1125 || (Entry = &ProcessData->HandleTable[Index])->Object == NULL)
1126 {
1127 DPRINT1("Couldn't dup invalid handle %p\n", Request->Data.DuplicateHandleRequest.Handle);
1128 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
1129 return STATUS_INVALID_HANDLE;
1130 }
1131
1132 if (Request->Data.DuplicateHandleRequest.Options & DUPLICATE_SAME_ACCESS)
1133 {
1134 DesiredAccess = Entry->Access;
1135 }
1136 else
1137 {
1138 DesiredAccess = Request->Data.DuplicateHandleRequest.Access;
1139 /* Make sure the source handle has all the desired flags */
1140 if (~Entry->Access & DesiredAccess)
1141 {
1142 DPRINT1("Handle %p only has access %X; requested %X\n",
1143 Request->Data.DuplicateHandleRequest.Handle, Entry->Access, DesiredAccess);
1144 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
1145 return STATUS_INVALID_PARAMETER;
1146 }
1147 }
1148
1149 Request->Status = CsrInsertObject(ProcessData,
1150 &Request->Data.DuplicateHandleRequest.Handle,
1151 Entry->Object,
1152 DesiredAccess,
1153 Request->Data.DuplicateHandleRequest.Inheritable);
1154 if (NT_SUCCESS(Request->Status)
1155 && Request->Data.DuplicateHandleRequest.Options & DUPLICATE_CLOSE_SOURCE)
1156 {
1157 /* Close the original handle. This cannot drop the count to 0, since a new handle now exists */
1158 _InterlockedDecrement(&Entry->Object->ReferenceCount);
1159 Entry->Object = NULL;
1160 }
1161
1162 RtlLeaveCriticalSection(&ProcessData->HandleTableLock);
1163 return Request->Status;
1164 }
1165
1166 CSR_API(CsrGetInputWaitHandle)
1167 {
1168 Request->Header.u1.s1.TotalLength = sizeof(CSR_API_MESSAGE);
1169 Request->Header.u1.s1.DataLength = sizeof(CSR_API_MESSAGE) - sizeof(PORT_MESSAGE);
1170
1171 Request->Data.GetConsoleInputWaitHandle.InputWaitHandle = ProcessData->ConsoleEvent;
1172 return STATUS_SUCCESS;
1173 }
1174
1175 /* EOF */