[REACTOS]
[reactos.git] / reactos / deprecated / csr / csrsrv / thread.c
1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS CSR Sub System
4 * FILE: subsys/csr/csrsrv/thread.c
5 * PURPOSE: CSR Server DLL Thread 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 LIST_ENTRY CsrThreadHashTable[256];
19 SECURITY_QUALITY_OF_SERVICE CsrSecurityQos =
20 {
21 sizeof(SECURITY_QUALITY_OF_SERVICE),
22 SecurityImpersonation,
23 SECURITY_STATIC_TRACKING,
24 FALSE
25 };
26
27 /* PRIVATE FUNCTIONS *********************************************************/
28
29 /*++
30 * @name CsrAllocateThread
31 *
32 * The CsrAllocateThread routine allocates a new CSR Thread object.
33 *
34 * @param CsrProcess
35 * Pointer to the CSR Process which will contain this CSR Thread.
36 *
37 * @return Pointer to the newly allocated CSR Thread.
38 *
39 * @remarks None.
40 *
41 *--*/
42 PCSR_THREAD
43 NTAPI
44 CsrAllocateThread(IN PCSR_PROCESS CsrProcess)
45 {
46 PCSR_THREAD CsrThread;
47
48 /* Allocate the structure */
49 CsrThread = RtlAllocateHeap(CsrHeap, HEAP_ZERO_MEMORY, sizeof(CSR_THREAD));
50 if (!CsrThread) return NULL;
51
52 /* Reference the Thread and Process */
53 CsrThread->ReferenceCount++;
54 CsrProcess->ReferenceCount++;
55
56 /* Set the Parent Process */
57 CsrThread->Process = CsrProcess;
58
59 /* Return Thread */
60 return CsrThread;
61 }
62
63 /*++
64 * @name CsrLocateThreadByClientId
65 *
66 * The CsrLocateThreadByClientId routine locates the CSR Thread and,
67 * optionally, its parent CSR Process, corresponding to a Client ID.
68 *
69 * @param Process
70 * Optional pointer to a CSR Process pointer which will contain
71 * the CSR Thread's parent.
72 *
73 * @param ClientId
74 * Pointer to a Client ID structure containing the Unique Thread ID
75 * to look up.
76 *
77 * @return Pointer to the CSR Thread corresponding to this CID, or NULL if
78 * none was found.
79 *
80 * @remarks None.
81 *
82 *--*/
83 PCSR_THREAD
84 NTAPI
85 CsrLocateThreadByClientId(OUT PCSR_PROCESS *Process OPTIONAL,
86 IN PCLIENT_ID ClientId)
87 {
88 ULONG i;
89 PLIST_ENTRY NextEntry;
90 PCSR_THREAD FoundThread;
91 ASSERT(ProcessStructureListLocked());
92
93 /* Hash the Thread */
94 i = CsrHashThread(ClientId->UniqueThread);
95
96 /* Set the list pointers */
97 NextEntry = CsrThreadHashTable[i].Flink;
98
99 /* Star the loop */
100 while (NextEntry != &CsrThreadHashTable[i])
101 {
102 /* Get the thread */
103 FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks);
104
105 /* Compare the CID */
106 if (*(PULONGLONG)&FoundThread->ClientId == *(PULONGLONG)ClientId)
107 {
108 /* Match found, return the process */
109 *Process = FoundThread->Process;
110
111 /* Return thread too */
112 return FoundThread;
113 }
114
115 /* Next */
116 NextEntry = NextEntry->Flink;
117 }
118
119 /* Nothing found */
120 return NULL;
121 }
122
123 /*++
124 * @name CsrLocateThreadInProcess
125 *
126 * The CsrLocateThreadInProcess routine locates the CSR Thread
127 * corresponding to a Client ID inside a specific CSR Process.
128 *
129 * @param Process
130 * Optional pointer to the CSR Process which contains the CSR Thread
131 * that will be looked up.
132 *
133 * @param ClientId
134 * Pointer to a Client ID structure containing the Unique Thread ID
135 * to look up.
136 *
137 * @return Pointer to the CSR Thread corresponding to this CID, or NULL if
138 * none was found.
139 *
140 * @remarks If the CsrProcess argument is NULL, the lookup will be done inside
141 * CsrRootProcess.
142 *
143 *--*/
144 PCSR_THREAD
145 NTAPI
146 CsrLocateThreadInProcess(IN PCSR_PROCESS CsrProcess OPTIONAL,
147 IN PCLIENT_ID Cid)
148 {
149 PLIST_ENTRY NextEntry;
150 PCSR_THREAD FoundThread = NULL;
151
152 /* Use the Root Process if none was specified */
153 if (!CsrProcess) CsrProcess = CsrRootProcess;
154
155 /* Save the List pointers */
156 NextEntry = CsrProcess->ThreadList.Flink;
157
158 /* Start the Loop */
159 while (NextEntry != &CsrProcess->ThreadList)
160 {
161 /* Get Thread Entry */
162 FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
163
164 /* Check for TID Match */
165 if (FoundThread->ClientId.UniqueThread == Cid->UniqueThread) break;
166
167 /* Next entry */
168 NextEntry = NextEntry->Flink;
169 }
170
171 /* Return what we found */
172 return FoundThread;
173 }
174
175 /*++
176 * @name CsrInsertThread
177 *
178 * The CsrInsertThread routine inserts a CSR Thread into its parent's
179 * Thread List and into the Thread Hash Table.
180 *
181 * @param Process
182 * Pointer to the CSR Process containing this CSR Thread.
183 *
184 * @param Thread
185 * Pointer to the CSR Thread to be inserted.
186 *
187 * @return None.
188 *
189 * @remarks None.
190 *
191 *--*/
192 VOID
193 NTAPI
194 CsrInsertThread(IN PCSR_PROCESS Process,
195 IN PCSR_THREAD Thread)
196 {
197 ULONG i;
198 ASSERT(ProcessStructureListLocked());
199
200 /* Insert it into the Regular List */
201 InsertTailList(&Process->ThreadList, &Thread->Link);
202
203 /* Increase Thread Count */
204 Process->ThreadCount++;
205
206 /* Hash the Thread */
207 i = CsrHashThread(Thread->ClientId.UniqueThread);
208
209 /* Insert it there too */
210 InsertHeadList(&CsrThreadHashTable[i], &Thread->HashLinks);
211 }
212
213 /*++
214 * @name CsrDeallocateThread
215 *
216 * The CsrDeallocateThread frees the memory associated with a CSR Thread.
217 *
218 * @param CsrThread
219 * Pointer to the CSR Thread to be freed.
220 *
221 * @return None.
222 *
223 * @remarks Do not call this routine. It is reserved for the internal
224 * thread management routines when a CSR Thread has been cleanly
225 * dereferenced and killed.
226 *
227 *--*/
228 VOID
229 NTAPI
230 CsrDeallocateThread(IN PCSR_THREAD CsrThread)
231 {
232 /* Free the process object from the heap */
233 ASSERT(CsrThread->WaitBlock == NULL);
234 RtlFreeHeap(CsrHeap, 0, CsrThread);
235 }
236
237 /*++
238 * @name CsrLockedReferenceThread
239 *
240 * The CsrLockedReferenceThread refences a CSR Thread while the
241 * Process Lock is already being held.
242 *
243 * @param CsrThread
244 * Pointer to the CSR Thread to be referenced.
245 *
246 * @return None.
247 *
248 * @remarks This routine will return with the Process Lock held.
249 *
250 *--*/
251 VOID
252 NTAPI
253 CsrLockedReferenceThread(IN PCSR_THREAD CsrThread)
254 {
255 /* Increment the reference count */
256 ++CsrThread->ReferenceCount;
257 }
258
259 /*++
260 * @name CsrLockedDereferenceThread
261 *
262 * The CsrLockedDereferenceThread derefences a CSR Thread while the
263 * Process Lock is already being held.
264 *
265 * @param CsrThread
266 * Pointer to the CSR Thread 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 CsrLockedDereferenceThread(IN PCSR_THREAD CsrThread)
276 {
277 LONG LockCount;
278
279 /* Decrease reference count */
280 LockCount = --CsrThread->ReferenceCount;
281 ASSERT(LockCount >= 0);
282 if (!LockCount)
283 {
284 /* Call the generic cleanup code */
285 CsrThreadRefcountZero(CsrThread);
286 CsrAcquireProcessLock();
287 }
288 }
289
290 /*++
291 * @name CsrRemoveThread
292 *
293 * The CsrRemoveThread function undoes a CsrInsertThread operation and
294 * removes the CSR Thread from the the Hash Table and Thread List.
295 *
296 * @param CsrThread
297 * Pointer to the CSR Thread to remove.
298 *
299 * @return None.
300 *
301 * @remarks If this CSR Thread is the last one inside a CSR Process, the
302 * parent will be dereferenced and the CsrProcessLastThreadTerminated
303 * flag will be set.
304 *
305 * After executing this routine, the CSR Thread will have the
306 * CsrThreadInTermination flag set.
307 *
308 *--*/
309 VOID
310 NTAPI
311 CsrRemoveThread(IN PCSR_THREAD CsrThread)
312 {
313 ASSERT(ProcessStructureListLocked());
314
315 /* Remove it from the List */
316 RemoveEntryList(&CsrThread->Link);
317
318 /* Decreate the thread count of the process */
319 --CsrThread->Process->ThreadCount;
320
321 /* Remove it from the Hash List as well */
322 if (CsrThread->HashLinks.Flink) RemoveEntryList(&CsrThread->HashLinks);
323
324 /* Check if this is the last Thread */
325 if (!CsrThread->Process->ThreadCount)
326 {
327 /* Check if it's not already been marked for deletion */
328 if (!(CsrThread->Process->Flags & CsrProcessLastThreadTerminated))
329 {
330 /* Let everyone know this process is about to lose the thread */
331 CsrThread->Process->Flags |= CsrProcessLastThreadTerminated;
332
333 /* Reference the Process */
334 CsrLockedDereferenceProcess(CsrThread->Process);
335 }
336 }
337
338 /* Mark the thread for deletion */
339 CsrThread->Flags |= CsrThreadInTermination;
340 }
341
342 /*++
343 * @name CsrThreadRefcountZero
344 *
345 * The CsrThreadRefcountZero routine is executed when a CSR Thread has lost
346 * all its active references. It removes and de-allocates the CSR Thread.
347 *
348 * @param CsrThread
349 * Pointer to the CSR Thread that is to be deleted.
350 *
351 * @return None.
352 *
353 * @remarks Do not call this routine. It is reserved for the internal
354 * thread management routines when a CSR Thread has lost all
355 * its references.
356 *
357 * This routine is called with the Process Lock held.
358 *
359 *--*/
360 VOID
361 NTAPI
362 CsrThreadRefcountZero(IN PCSR_THREAD CsrThread)
363 {
364 PCSR_PROCESS CsrProcess = CsrThread->Process;
365 NTSTATUS Status;
366
367 /* Remove this thread */
368 CsrRemoveThread(CsrThread);
369
370 /* Release the Process Lock */
371 CsrReleaseProcessLock();
372
373 /* Close the NT Thread Handle */
374 UnProtectHandle(CsrThread->ThreadHandle);
375 Status = NtClose(CsrThread->ThreadHandle);
376 ASSERT(NT_SUCCESS(Status));
377
378 /* De-allocate the CSR Thread Object */
379 CsrDeallocateThread(CsrThread);
380
381 /* Remove a reference from the process */
382 CsrDereferenceProcess(CsrProcess);
383 }
384
385 /* PUBLIC FUNCTIONS ***********************************************************/
386
387 /*++
388 * @name CsrAddStaticServerThread
389 * @implemented NT4
390 *
391 * The CsrAddStaticServerThread routine adds a new CSR Thread to the
392 * CSR Server Process (CsrRootProcess).
393 *
394 * @param hThread
395 * Handle to an existing NT Thread to which to associate this
396 * CSR Thread.
397 *
398 * @param ClientId
399 * Pointer to the Client ID structure of the NT Thread to associate
400 * with this CSR Thread.
401 *
402 * @param ThreadFlags
403 * Initial CSR Thread Flags to associate to this CSR Thread. Usually
404 * CsrThreadIsServerThread.
405 *
406 * @return Pointer to the newly allocated CSR Thread.
407 *
408 * @remarks None.
409 *
410 *--*/
411 PCSR_THREAD
412 NTAPI
413 CsrAddStaticServerThread(IN HANDLE hThread,
414 IN PCLIENT_ID ClientId,
415 IN ULONG ThreadFlags)
416 {
417 PCSR_THREAD CsrThread;
418
419 /* Get the Lock */
420 CsrAcquireProcessLock();
421
422 /* Allocate the Server Thread */
423 CsrThread = CsrAllocateThread(CsrRootProcess);
424 if (CsrThread)
425 {
426 /* Setup the Object */
427 CsrThread->ThreadHandle = hThread;
428 ProtectHandle(hThread);
429 CsrThread->ClientId = *ClientId;
430 CsrThread->Flags = ThreadFlags;
431
432 /* Insert it into the Thread List */
433 InsertTailList(&CsrRootProcess->ThreadList, &CsrThread->Link);
434
435 /* Increment the thread count */
436 CsrRootProcess->ThreadCount++;
437 }
438 else
439 {
440 DPRINT1("CsrAddStaticServerThread: alloc failed for thread 0x%x\n", hThread);
441 }
442
443 /* Release the Process Lock and return */
444 CsrReleaseProcessLock();
445 return CsrThread;
446 }
447
448 /*++
449 * @name CsrCreateRemoteThread
450 * @implemented NT4
451 *
452 * The CsrCreateRemoteThread routine creates a CSR Thread object for
453 * an NT Thread which is not part of the current NT Process.
454 *
455 * @param hThread
456 * Handle to an existing NT Thread to which to associate this
457 * CSR Thread.
458 *
459 * @param ClientId
460 * Pointer to the Client ID structure of the NT Thread to associate
461 * with this CSR Thread.
462 *
463 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
464 * othwerwise.
465 *
466 * @remarks None.
467 *
468 *--*/
469 NTSTATUS
470 NTAPI
471 CsrCreateRemoteThread(IN HANDLE hThread,
472 IN PCLIENT_ID ClientId)
473 {
474 NTSTATUS Status;
475 HANDLE ThreadHandle;
476 PCSR_THREAD CsrThread;
477 PCSR_PROCESS CsrProcess;
478 KERNEL_USER_TIMES KernelTimes;
479
480 DPRINT("CSRSRV: %s called\n", __FUNCTION__);
481
482 /* Get the Thread Create Time */
483 Status = NtQueryInformationThread(hThread,
484 ThreadTimes,
485 &KernelTimes,
486 sizeof(KernelTimes),
487 NULL);
488 if (!NT_SUCCESS(Status)) return Status;
489
490 /* Lock the Owner Process */
491 Status = CsrLockProcessByClientId(&ClientId->UniqueProcess, &CsrProcess);
492
493 /* Make sure the thread didn't terminate */
494 if (KernelTimes.ExitTime.QuadPart)
495 {
496 /* Unlock the process and return */
497 CsrUnlockProcess(CsrProcess);
498 return STATUS_THREAD_IS_TERMINATING;
499 }
500
501 /* Allocate a CSR Thread Structure */
502 CsrThread = CsrAllocateThread(CsrProcess);
503 if (!CsrThread)
504 {
505 DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__);
506 CsrUnlockProcess(CsrProcess);
507 return STATUS_NO_MEMORY;
508 }
509
510 /* Duplicate the Thread Handle */
511 Status = NtDuplicateObject(NtCurrentProcess(),
512 hThread,
513 NtCurrentProcess(),
514 &ThreadHandle,
515 0,
516 0,
517 DUPLICATE_SAME_ACCESS);
518 /* Allow failure */
519 if (!NT_SUCCESS(Status)) ThreadHandle = hThread;
520
521 /* Save the data we have */
522 CsrThread->CreateTime = KernelTimes.CreateTime;
523 CsrThread->ClientId = *ClientId;
524 CsrThread->ThreadHandle = ThreadHandle;
525 ProtectHandle(ThreadHandle);
526 CsrThread->Flags = 0;
527
528 /* Insert the Thread into the Process */
529 CsrInsertThread(CsrProcess, CsrThread);
530
531 /* Release the lock and return */
532 CsrUnlockProcess(CsrProcess);
533 return STATUS_SUCCESS;
534 }
535
536 /*++
537 * @name CsrCreateThread
538 * @implemented NT4
539 *
540 * The CsrCreateThread routine creates a CSR Thread object for an NT Thread.
541 *
542 * @param CsrProcess
543 * Pointer to the CSR Process which will contain the CSR Thread.
544 *
545 * @param hThread
546 * Handle to an existing NT Thread to which to associate this
547 * CSR Thread.
548 *
549 * @param ClientId
550 * Pointer to the Client ID structure of the NT Thread to associate
551 * with this CSR Thread.
552 *
553 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
554 * othwerwise.
555 *
556 * @remarks None.
557 *
558 *--*/
559 NTSTATUS
560 NTAPI
561 CsrCreateThread(IN PCSR_PROCESS CsrProcess,
562 IN HANDLE hThread,
563 IN PCLIENT_ID ClientId,
564 IN BOOLEAN HaveClient)
565 {
566 NTSTATUS Status;
567 PCSR_THREAD CsrThread, CurrentThread;
568 PCSR_PROCESS CurrentProcess;
569 CLIENT_ID CurrentCid;
570 KERNEL_USER_TIMES KernelTimes;
571 DPRINT("CSRSRV: %s called\n", __FUNCTION__);
572
573 if (HaveClient)
574 {
575 /* Get the current thread and CID */
576 CurrentThread = NtCurrentTeb()->CsrClientThread;
577 CurrentCid = CurrentThread->ClientId;
578
579 /* Acquire the Process Lock */
580 CsrAcquireProcessLock();
581
582 /* Get the current Process and make sure the Thread is valid with this CID */
583 CurrentThread = CsrLocateThreadByClientId(&CurrentProcess, &CurrentCid);
584 if (!CurrentThread)
585 {
586 DPRINT1("CSRSRV:%s: invalid thread!\n", __FUNCTION__);
587 CsrReleaseProcessLock();
588 return STATUS_THREAD_IS_TERMINATING;
589 }
590 }
591 else
592 {
593 /* Acquire the Process Lock */
594 CsrAcquireProcessLock();
595 }
596
597 /* Get the Thread Create Time */
598 Status = NtQueryInformationThread(hThread,
599 ThreadTimes,
600 (PVOID)&KernelTimes,
601 sizeof(KernelTimes),
602 NULL);
603 if (!NT_SUCCESS(Status))
604 {
605 CsrReleaseProcessLock();
606 return Status;
607 }
608
609 /* Allocate a CSR Thread Structure */
610 CsrThread = CsrAllocateThread(CsrProcess);
611 if (!CsrThread)
612 {
613 DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__);
614 CsrReleaseProcessLock();
615 return STATUS_NO_MEMORY;
616 }
617
618 /* Save the data we have */
619 CsrThread->CreateTime = KernelTimes.CreateTime;
620 CsrThread->ClientId = *ClientId;
621 CsrThread->ThreadHandle = hThread;
622 ProtectHandle(hThread);
623 CsrThread->Flags = 0;
624
625 /* Insert the Thread into the Process */
626 CsrInsertThread(CsrProcess, CsrThread);
627
628 /* Release the lock and return */
629 CsrReleaseProcessLock();
630 return STATUS_SUCCESS;
631 }
632
633 /*++
634 * @name CsrDereferenceThread
635 * @implemented NT4
636 *
637 * The CsrDereferenceThread routine removes a reference from a CSR Thread.
638 *
639 * @param CsrThread
640 * Pointer to the CSR Thread to dereference.
641 *
642 * @return None.
643 *
644 * @remarks If the reference count has reached zero (ie: the CSR Thread has
645 * no more active references), it will be deleted.
646 *
647 *--*/
648 VOID
649 NTAPI
650 CsrDereferenceThread(IN PCSR_THREAD CsrThread)
651 {
652 /* Acquire process lock */
653 CsrAcquireProcessLock();
654
655 /* Decrease reference count */
656 ASSERT(CsrThread->ReferenceCount > 0);
657 if (!(--CsrThread->ReferenceCount))
658 {
659 /* Call the generic cleanup code */
660 CsrThreadRefcountZero(CsrThread);
661 }
662 else
663 {
664 /* Just release the lock */
665 CsrReleaseProcessLock();
666 }
667 }
668
669 /*++
670 * @name CsrExecServerThread
671 * @implemented NT4
672 *
673 * The CsrExecServerThread routine creates an NT Thread and then
674 * initializes a CSR Thread for it.
675 *
676 * @param ThreadHandler
677 * Pointer to the thread's startup routine.
678 *
679 * @param Flags
680 * Initial CSR Thread Flags to set to the CSR Thread.
681 *
682 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
683 * othwerwise.
684 *
685 * @remarks This routine is similar to CsrAddStaticServerThread, but it
686 * also creates an NT Thread instead of expecting one to already
687 * exist.
688 *
689 *--*/
690 NTSTATUS
691 NTAPI
692 CsrExecServerThread(IN PVOID ThreadHandler,
693 IN ULONG Flags)
694 {
695 PCSR_THREAD CsrThread;
696 HANDLE hThread;
697 CLIENT_ID ClientId;
698 NTSTATUS Status;
699
700 /* Acquire process lock */
701 CsrAcquireProcessLock();
702
703 /* Allocate a CSR Thread in the Root Process */
704 ASSERT(CsrRootProcess != NULL);
705 CsrThread = CsrAllocateThread(CsrRootProcess);
706 if (!CsrThread)
707 {
708 /* Fail */
709 CsrReleaseProcessLock();
710 return STATUS_NO_MEMORY;
711 }
712
713 /* Create the Thread */
714 Status = RtlCreateUserThread(NtCurrentProcess(),
715 NULL,
716 FALSE,
717 0,
718 0,
719 0,
720 ThreadHandler,
721 NULL,
722 &hThread,
723 &ClientId);
724 if (!NT_SUCCESS(Status))
725 {
726 /* Fail */
727 CsrDeallocateThread(CsrThread);
728 CsrReleaseProcessLock();
729 return Status;
730 }
731
732 /* Setup the Thread Object */
733 CsrThread->ThreadHandle = hThread;
734 ProtectHandle(hThread);
735 CsrThread->ClientId = ClientId;
736 CsrThread->Flags = Flags;
737
738 /* Insert it into the Thread List */
739 InsertHeadList(&CsrRootProcess->ThreadList, &CsrThread->Link);
740
741 /* Increase the thread count */
742 CsrRootProcess->ThreadCount++;
743
744 /* Return */
745 CsrReleaseProcessLock();
746 return Status;
747 }
748
749 /*++
750 * @name CsrDestroyThread
751 * @implemented NT4
752 *
753 * The CsrDestroyThread routine destroys the CSR Thread corresponding to
754 * a given Thread ID.
755 *
756 * @param Cid
757 * Pointer to the Client ID Structure corresponding to the CSR
758 * Thread which is about to be destroyed.
759 *
760 * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING
761 * if the CSR Thread is already terminating.
762 *
763 * @remarks None.
764 *
765 *--*/
766 NTSTATUS
767 NTAPI
768 CsrDestroyThread(IN PCLIENT_ID Cid)
769 {
770 CLIENT_ID ClientId = *Cid;
771 PCSR_THREAD CsrThread;
772 PCSR_PROCESS CsrProcess;
773
774 /* Acquire lock */
775 CsrAcquireProcessLock();
776
777 /* Find the thread */
778 CsrThread = CsrLocateThreadByClientId(&CsrProcess,
779 &ClientId);
780
781 /* Make sure we got one back, and that it's not already gone */
782 if (!CsrThread || CsrThread->Flags & CsrThreadTerminated)
783 {
784 /* Release the lock and return failure */
785 CsrReleaseProcessLock();
786 return STATUS_THREAD_IS_TERMINATING;
787 }
788
789 /* Set the terminated flag */
790 CsrThread->Flags |= CsrThreadTerminated;
791
792 /* Acquire the Wait Lock */
793 CsrAcquireWaitLock();
794
795 /* Do we have an active wait block? */
796 if (CsrThread->WaitBlock)
797 {
798 /* Notify waiters of termination */
799 CsrNotifyWaitBlock(CsrThread->WaitBlock,
800 NULL,
801 NULL,
802 NULL,
803 CsrProcessTerminating,
804 TRUE);
805 }
806
807 /* Release the Wait Lock */
808 CsrReleaseWaitLock();
809
810 /* Dereference the thread */
811 CsrLockedDereferenceThread(CsrThread);
812
813 /* Release the Process Lock and return success */
814 CsrReleaseProcessLock();
815 return STATUS_SUCCESS;
816 }
817
818 /*++
819 * @name CsrImpersonateClient
820 * @implemented NT4
821 *
822 * The CsrImpersonateClient will impersonate the given CSR Thread.
823 *
824 * @param CsrThread
825 * Pointer to the CSR Thread to impersonate.
826 *
827 * @return TRUE if impersionation suceeded, false otherwise.
828 *
829 * @remarks Impersonation can be recursive.
830 *
831 *--*/
832 BOOLEAN
833 NTAPI
834 CsrImpersonateClient(IN PCSR_THREAD CsrThread)
835 {
836 NTSTATUS Status;
837 PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
838
839 /* Use the current thread if none given */
840 if (!CsrThread) CsrThread = CurrentThread;
841
842 /* Still no thread, something is wrong */
843 if (!CsrThread) return FALSE;
844
845 /* Make the call */
846 Status = NtImpersonateThread(NtCurrentThread(),
847 CsrThread->ThreadHandle,
848 &CsrSecurityQos);
849 if (!NT_SUCCESS(Status))
850 {
851 DPRINT1("CSRSS: Can't impersonate client thread - Status = %lx\n", Status);
852 if (Status != STATUS_BAD_IMPERSONATION_LEVEL) DbgBreakPoint();
853 return FALSE;
854 }
855
856 /* Increase the impersonation count for the current thread and return */
857 if (CurrentThread) ++CurrentThread->ImpersonationCount;
858 return TRUE;
859 }
860
861 /*++
862 * @name CsrRevertToSelf
863 * @implemented NT4
864 *
865 * The CsrRevertToSelf routine will attempt to remove an active impersonation.
866 *
867 * @param None.
868 *
869 * @return TRUE if the reversion was succesful, false otherwise.
870 *
871 * @remarks Impersonation can be recursive; as such, the impersonation token
872 * will only be deleted once the CSR Thread's impersonaton count
873 * has reached zero.
874 *
875 *--*/
876 BOOLEAN
877 NTAPI
878 CsrRevertToSelf(VOID)
879 {
880 NTSTATUS Status;
881 PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
882 HANDLE ImpersonationToken = NULL;
883
884 /* Check if we have a Current Thread */
885 if (CurrentThread)
886 {
887 /* Make sure impersonation is on */
888 if (!CurrentThread->ImpersonationCount)
889 {
890 DPRINT1("CSRSS: CsrRevertToSelf called while not impersonating\n");
891 DbgBreakPoint();
892 return FALSE;
893 }
894 else if (--CurrentThread->ImpersonationCount > 0)
895 {
896 /* Success; impersonation count decreased but still not zero */
897 return TRUE;
898 }
899 }
900
901 /* Impersonation has been totally removed, revert to ourselves */
902 Status = NtSetInformationThread(NtCurrentThread(),
903 ThreadImpersonationToken,
904 &ImpersonationToken,
905 sizeof(HANDLE));
906
907 /* Return TRUE or FALSE */
908 ASSERT(NT_SUCCESS(Status));
909 return NT_SUCCESS(Status);
910 }
911
912 /*++
913 * @name CsrLockThreadByClientId
914 * @implemented NT4
915 *
916 * The CsrLockThreadByClientId routine locks the CSR Thread corresponding
917 * to the given Thread ID and optionally returns it.
918 *
919 * @param Tid
920 * Thread ID corresponding to the CSR Thread which will be locked.
921 *
922 * @param CsrThread
923 * Optional pointer to a CSR Thread pointer which will hold the
924 * CSR Thread corresponding to the given Thread ID.
925 *
926 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
927 * othwerwise.
928 *
929 * @remarks Locking a CSR Thread is defined as acquiring an extra
930 * reference to it and returning with the Process Lock held.
931 *
932 *--*/
933 NTSTATUS
934 NTAPI
935 CsrLockThreadByClientId(IN HANDLE Tid,
936 OUT PCSR_THREAD *CsrThread)
937 {
938 PLIST_ENTRY NextEntry;
939 PCSR_THREAD CurrentThread = NULL;
940 NTSTATUS Status = STATUS_UNSUCCESSFUL;
941 ULONG i;
942
943 /* Acquire the lock */
944 CsrAcquireProcessLock();
945
946 /* Assume failure */
947 ASSERT(CsrThread != NULL);
948 *CsrThread = NULL;
949
950 /* Convert to Hash */
951 i = CsrHashThread(Tid);
952
953 /* Setup the List Pointers */
954 NextEntry = CsrThreadHashTable[i].Flink;
955
956 /* Start Loop */
957 while (NextEntry != &CsrThreadHashTable[i])
958 {
959 /* Get the Process */
960 CurrentThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks);
961
962 /* Check for PID Match */
963 if ((CurrentThread->ClientId.UniqueThread == Tid) &&
964 !(CurrentThread->Flags & CsrThreadTerminated))
965 {
966 /* Get out of here */
967 break;
968 }
969
970 /* Next entry */
971 NextEntry = NextEntry->Flink;
972 }
973
974 /* Nothing found if we got back to the list */
975 if (NextEntry == &CsrThreadHashTable[i]) CurrentThread = NULL;
976
977 /* Did the loop find something? */
978 if (CurrentThread)
979 {
980 /* Reference the found thread */
981 Status = STATUS_SUCCESS;
982 CurrentThread->ReferenceCount++;
983 *CsrThread = CurrentThread;
984 }
985 else
986 {
987 /* Nothing found, release the lock */
988 Status = STATUS_UNSUCCESSFUL;
989 CsrReleaseProcessLock();
990 }
991
992 /* Return the status */
993 return Status;
994 }
995
996 /*++
997 * @name CsrReferenceThread
998 * @implemented NT4
999 *
1000 * The CsrReferenceThread routine increases the active reference count of
1001 * a CSR Thread.
1002 *
1003 * @param CsrThread
1004 * Pointer to the CSR Thread whose reference count will be increased.
1005 *
1006 * @return None.
1007 *
1008 * @remarks Do not use this routine if the Process Lock is already held.
1009 *
1010 *--*/
1011 VOID
1012 NTAPI
1013 CsrReferenceThread(PCSR_THREAD CsrThread)
1014 {
1015 /* Acquire process lock */
1016 CsrAcquireProcessLock();
1017
1018 /* Sanity checks */
1019 ASSERT(CsrThread->Flags & CsrThreadTerminated); // CSR_THREAD_DESTROYED in ASSERT
1020 ASSERT(CsrThread->ReferenceCount != 0);
1021
1022 /* Increment reference count */
1023 CsrThread->ReferenceCount++;
1024
1025 /* Release the lock */
1026 CsrReleaseProcessLock();
1027 }
1028
1029 /*++
1030 * @name CsrUnlockThread
1031 * @implemented NT4
1032 *
1033 * The CsrUnlockThread undoes a previous CsrLockThreadByClientId operation.
1034 *
1035 * @param CsrThread
1036 * Pointer to a previously locked CSR Thread.
1037 *
1038 * @return STATUS_SUCCESS.
1039 *
1040 * @remarks This routine must be called with the Process Lock held.
1041 *
1042 *--*/
1043 NTSTATUS
1044 NTAPI
1045 CsrUnlockThread(PCSR_THREAD CsrThread)
1046 {
1047 /* Dereference the Thread */
1048 ASSERT(ProcessStructureListLocked());
1049 CsrLockedDereferenceThread(CsrThread);
1050
1051 /* Release the lock and return */
1052 CsrReleaseProcessLock();
1053 return STATUS_SUCCESS;
1054 }
1055
1056 /* EOF */