[Win32k|User32]
[reactos.git] / reactos / subsystems / 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 ListHead, NextEntry;
90 PCSR_THREAD FoundThread;
91
92 /* Hash the Thread */
93 i = CsrHashThread(ClientId->UniqueThread);
94
95 /* Set the list pointers */
96 ListHead = &CsrThreadHashTable[i];
97 NextEntry = ListHead->Flink;
98
99 /* Star the loop */
100 while (NextEntry != ListHead)
101 {
102 /* Get the thread */
103 FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks);
104
105 /* Compare the CID */
106 if (FoundThread->ClientId.UniqueThread == ClientId->UniqueThread)
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 ListHead, 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 ListHead = &CsrProcess->ThreadList;
157 NextEntry = ListHead->Flink;
158
159 /* Start the Loop */
160 while (NextEntry != ListHead)
161 {
162 /* Get Thread Entry */
163 FoundThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, Link);
164
165 /* Check for TID Match */
166 if (FoundThread->ClientId.UniqueThread == Cid->UniqueThread) break;
167
168 /* Next entry */
169 NextEntry = NextEntry->Flink;
170 }
171
172 /* Return what we found */
173 return FoundThread;
174 }
175
176 /*++
177 * @name CsrInsertThread
178 *
179 * The CsrInsertThread routine inserts a CSR Thread into its parent's
180 * Thread List and into the Thread Hash Table.
181 *
182 * @param Process
183 * Pointer to the CSR Process containing this CSR Thread.
184 *
185 * @param Thread
186 * Pointer to the CSR Thread to be inserted.
187 *
188 * @return None.
189 *
190 * @remarks None.
191 *
192 *--*/
193 VOID
194 NTAPI
195 CsrInsertThread(IN PCSR_PROCESS Process,
196 IN PCSR_THREAD Thread)
197 {
198 ULONG i;
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 RtlFreeHeap(CsrHeap, 0, CsrThread);
234 }
235
236 /*++
237 * @name CsrLockedDereferenceThread
238 *
239 * The CsrLockedDereferenceThread derefences a CSR Thread while the
240 * Process Lock is already being held.
241 *
242 * @param CsrThread
243 * Pointer to the CSR Thread to be dereferenced.
244 *
245 * @return None.
246 *
247 * @remarks This routine will return with the Process Lock held.
248 *
249 *--*/
250 VOID
251 NTAPI
252 CsrLockedDereferenceThread(PCSR_THREAD CsrThread)
253 {
254 /* Decrease reference count */
255 if (!(--CsrThread->ReferenceCount))
256 {
257 /* Call the generic cleanup code */
258 CsrThreadRefcountZero(CsrThread);
259 CsrAcquireProcessLock();
260 }
261 }
262
263 /*++
264 * @name CsrRemoveThread
265 *
266 * The CsrRemoveThread function undoes a CsrInsertThread operation and
267 * removes the CSR Thread from the the Hash Table and Thread List.
268 *
269 * @param CsrThread
270 * Pointer to the CSR Thread to remove.
271 *
272 * @return None.
273 *
274 * @remarks If this CSR Thread is the last one inside a CSR Process, the
275 * parent will be dereferenced and the CsrProcessLastThreadTerminated
276 * flag will be set.
277 *
278 * After executing this routine, the CSR Thread will have the
279 * CsrThreadInTermination flag set.
280 *
281 *--*/
282 VOID
283 NTAPI
284 CsrRemoveThread(IN PCSR_THREAD CsrThread)
285 {
286 /* Remove it from the List */
287 RemoveEntryList(&CsrThread->Link);
288
289 /* Decreate the thread count of the process */
290 CsrThread->Process->ThreadCount--;
291
292 /* Remove it from the Hash List as well */
293 if (CsrThread->HashLinks.Flink) RemoveEntryList(&CsrThread->HashLinks);
294
295 /* Check if this is the last Thread */
296 if (!CsrThread->Process->ThreadCount)
297 {
298 /* Check if it's not already been marked for deletion */
299 if (!(CsrThread->Process->Flags & CsrProcessLastThreadTerminated))
300 {
301 /* Let everyone know this process is about to lose the thread */
302 CsrThread->Process->Flags |= CsrProcessLastThreadTerminated;
303
304 /* Reference the Process */
305 CsrLockedDereferenceProcess(CsrThread->Process);
306 }
307 }
308
309 /* Mark the thread for deletion */
310 CsrThread->Flags |= CsrThreadInTermination;
311 }
312
313 /*++
314 * @name CsrThreadRefcountZero
315 *
316 * The CsrThreadRefcountZero routine is executed when a CSR Thread has lost
317 * all its active references. It removes and de-allocates the CSR Thread.
318 *
319 * @param CsrThread
320 * Pointer to the CSR Thread that is to be deleted.
321 *
322 * @return None.
323 *
324 * @remarks Do not call this routine. It is reserved for the internal
325 * thread management routines when a CSR Thread has lost all
326 * its references.
327 *
328 * This routine is called with the Process Lock held.
329 *
330 *--*/
331 VOID
332 NTAPI
333 CsrThreadRefcountZero(IN PCSR_THREAD CsrThread)
334 {
335 PCSR_PROCESS CsrProcess = CsrThread->Process;
336
337 /* Remove this thread */
338 CsrRemoveThread(CsrThread);
339
340 /* Release the Process Lock */
341 CsrReleaseProcessLock();
342
343 /* Close the NT Thread Handle */
344 NtClose(CsrThread->ThreadHandle);
345
346 /* De-allocate the CSR Thread Object */
347 CsrDeallocateThread(CsrThread);
348
349 /* Remove a reference from the process */
350 CsrDereferenceProcess(CsrProcess);
351 }
352
353 /* PUBLIC FUNCTIONS ***********************************************************/
354
355 /*++
356 * @name CsrAddStaticServerThread
357 * @implemented NT4
358 *
359 * The CsrAddStaticServerThread routine adds a new CSR Thread to the
360 * CSR Server Process (CsrRootProcess).
361 *
362 * @param hThread
363 * Handle to an existing NT Thread to which to associate this
364 * CSR Thread.
365 *
366 * @param ClientId
367 * Pointer to the Client ID structure of the NT Thread to associate
368 * with this CSR Thread.
369 *
370 * @param ThreadFlags
371 * Initial CSR Thread Flags to associate to this CSR Thread. Usually
372 * CsrThreadIsServerThread.
373 *
374 * @return Pointer to the newly allocated CSR Thread.
375 *
376 * @remarks None.
377 *
378 *--*/
379 PCSR_THREAD
380 NTAPI
381 CsrAddStaticServerThread(IN HANDLE hThread,
382 IN PCLIENT_ID ClientId,
383 IN ULONG ThreadFlags)
384 {
385 PCSR_THREAD CsrThread;
386
387 /* Get the Lock */
388 CsrAcquireProcessLock();
389
390 /* Allocate the Server Thread */
391 if ((CsrThread = CsrAllocateThread(CsrRootProcess)))
392 {
393 /* Setup the Object */
394 CsrThread->ThreadHandle = hThread;
395 CsrThread->ClientId = *ClientId;
396 CsrThread->Flags = ThreadFlags;
397
398 /* Insert it into the Thread List */
399 InsertTailList(&CsrRootProcess->ThreadList, &CsrThread->Link);
400
401 /* Increment the thread count */
402 CsrRootProcess->ThreadCount++;
403 }
404
405 /* Release the Process Lock and return */
406 CsrReleaseProcessLock();
407 return CsrThread;
408 }
409
410 /*++
411 * @name CsrCreateRemoteThread
412 * @implemented NT4
413 *
414 * The CsrCreateRemoteThread routine creates a CSR Thread object for
415 * an NT Thread which is not part of the current NT Process.
416 *
417 * @param hThread
418 * Handle to an existing NT Thread to which to associate this
419 * CSR Thread.
420 *
421 * @param ClientId
422 * Pointer to the Client ID structure of the NT Thread to associate
423 * with this CSR Thread.
424 *
425 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
426 * othwerwise.
427 *
428 * @remarks None.
429 *
430 *--*/
431 NTSTATUS
432 NTAPI
433 CsrCreateRemoteThread(IN HANDLE hThread,
434 IN PCLIENT_ID ClientId)
435 {
436 NTSTATUS Status;
437 HANDLE ThreadHandle;
438 PCSR_THREAD CsrThread;
439 PCSR_PROCESS CsrProcess;
440 KERNEL_USER_TIMES KernelTimes;
441
442 DPRINT("CSRSRV: %s called\n", __FUNCTION__);
443
444 /* Get the Thread Create Time */
445 Status = NtQueryInformationThread(hThread,
446 ThreadTimes,
447 (PVOID)&KernelTimes,
448 sizeof(KernelTimes),
449 NULL);
450
451 /* Lock the Owner Process */
452 Status = CsrLockProcessByClientId(&ClientId->UniqueProcess,
453 &CsrProcess);
454
455 /* Make sure the thread didn't terminate */
456 if (KernelTimes.ExitTime.QuadPart)
457 {
458 /* Unlock the process and return */
459 CsrUnlockProcess(CsrProcess);
460 return STATUS_THREAD_IS_TERMINATING;
461 }
462
463 /* Allocate a CSR Thread Structure */
464 if (!(CsrThread = CsrAllocateThread(CsrProcess)))
465 {
466 DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__);
467 CsrUnlockProcess(CsrProcess);
468 return STATUS_NO_MEMORY;
469 }
470
471 /* Duplicate the Thread Handle */
472 Status = NtDuplicateObject(NtCurrentProcess(),
473 hThread,
474 NtCurrentProcess(),
475 &ThreadHandle,
476 0,
477 0,
478 DUPLICATE_SAME_ACCESS);
479 /* Allow failure */
480 if (!NT_SUCCESS(Status)) ThreadHandle = hThread;
481
482 /* Save the data we have */
483 CsrThread->CreateTime = KernelTimes.CreateTime;
484 CsrThread->ClientId = *ClientId;
485 CsrThread->ThreadHandle = ThreadHandle;
486 CsrThread->Flags = 0;
487
488 /* Insert the Thread into the Process */
489 CsrInsertThread(CsrProcess, CsrThread);
490
491 /* Release the lock and return */
492 CsrUnlockProcess(CsrProcess);
493 return STATUS_SUCCESS;
494 }
495
496 /*++
497 * @name CsrCreateThread
498 * @implemented NT4
499 *
500 * The CsrCreateThread routine creates a CSR Thread object for an NT Thread.
501 *
502 * @param CsrProcess
503 * Pointer to the CSR Process which will contain the CSR Thread.
504 *
505 * @param hThread
506 * Handle to an existing NT Thread to which to associate this
507 * CSR Thread.
508 *
509 * @param ClientId
510 * Pointer to the Client ID structure of the NT Thread to associate
511 * with this CSR Thread.
512 *
513 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
514 * othwerwise.
515 *
516 * @remarks None.
517 *
518 *--*/
519 NTSTATUS
520 NTAPI
521 CsrCreateThread(IN PCSR_PROCESS CsrProcess,
522 IN HANDLE hThread,
523 IN PCLIENT_ID ClientId)
524 {
525 NTSTATUS Status;
526 PCSR_THREAD CsrThread;
527 PCSR_PROCESS CurrentProcess;
528 PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
529 CLIENT_ID CurrentCid;
530 KERNEL_USER_TIMES KernelTimes;
531
532 DPRINT("CSRSRV: %s called\n", __FUNCTION__);
533
534 /* Get the current thread and CID */
535 CurrentCid = CurrentThread->ClientId;
536
537 /* Acquire the Process Lock */
538 CsrAcquireProcessLock();
539
540 /* Get the current Process and make sure the Thread is valid with this CID */
541 CurrentThread = CsrLocateThreadByClientId(&CurrentProcess,
542 &CurrentCid);
543
544 /* Something is wrong if we get an empty thread back */
545 if (!CurrentThread)
546 {
547 DPRINT1("CSRSRV:%s: invalid thread!\n", __FUNCTION__);
548 CsrReleaseProcessLock();
549 return STATUS_THREAD_IS_TERMINATING;
550 }
551
552 /* Get the Thread Create Time */
553 Status = NtQueryInformationThread(hThread,
554 ThreadTimes,
555 (PVOID)&KernelTimes,
556 sizeof(KernelTimes),
557 NULL);
558
559 /* Allocate a CSR Thread Structure */
560 if (!(CsrThread = CsrAllocateThread(CsrProcess)))
561 {
562 DPRINT1("CSRSRV:%s: out of memory!\n", __FUNCTION__);
563 CsrReleaseProcessLock();
564 return STATUS_NO_MEMORY;
565 }
566
567 /* Save the data we have */
568 CsrThread->CreateTime = KernelTimes.CreateTime;
569 CsrThread->ClientId = *ClientId;
570 CsrThread->ThreadHandle = hThread;
571 CsrThread->Flags = 0;
572
573 /* Insert the Thread into the Process */
574 CsrInsertThread(CsrProcess, CsrThread);
575
576 /* Release the lock and return */
577 CsrReleaseProcessLock();
578 return STATUS_SUCCESS;
579 }
580
581 /*++
582 * @name CsrDereferenceThread
583 * @implemented NT4
584 *
585 * The CsrDereferenceThread routine removes a reference from a CSR Thread.
586 *
587 * @param CsrThread
588 * Pointer to the CSR Thread to dereference.
589 *
590 * @return None.
591 *
592 * @remarks If the reference count has reached zero (ie: the CSR Thread has
593 * no more active references), it will be deleted.
594 *
595 *--*/
596 VOID
597 NTAPI
598 CsrDereferenceThread(PCSR_THREAD CsrThread)
599 {
600 /* Acquire process lock */
601 CsrAcquireProcessLock();
602
603 /* Decrease reference count */
604 if (!(--CsrThread->ReferenceCount))
605 {
606 /* Call the generic cleanup code */
607 CsrThreadRefcountZero(CsrThread);
608 }
609 else
610 {
611 /* Just release the lock */
612 CsrReleaseProcessLock();
613 }
614 }
615
616 /*++
617 * @name CsrExecServerThread
618 * @implemented NT4
619 *
620 * The CsrExecServerThread routine creates an NT Thread and then
621 * initializes a CSR Thread for it.
622 *
623 * @param ThreadHandler
624 * Pointer to the thread's startup routine.
625 *
626 * @param Flags
627 * Initial CSR Thread Flags to set to the CSR Thread.
628 *
629 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
630 * othwerwise.
631 *
632 * @remarks This routine is similar to CsrAddStaticServerThread, but it
633 * also creates an NT Thread instead of expecting one to already
634 * exist.
635 *
636 *--*/
637 NTSTATUS
638 NTAPI
639 CsrExecServerThread(IN PVOID ThreadHandler,
640 IN ULONG Flags)
641 {
642 PCSR_THREAD CsrThread;
643 HANDLE hThread;
644 CLIENT_ID ClientId;
645 NTSTATUS Status;
646
647 /* Acquire process lock */
648 CsrAcquireProcessLock();
649
650 /* Allocate a CSR Thread in the Root Process */
651 if (!(CsrThread = CsrAllocateThread(CsrRootProcess)))
652 {
653 /* Fail */
654 CsrReleaseProcessLock();
655 return STATUS_NO_MEMORY;
656 }
657
658 /* Create the Thread */
659 Status = RtlCreateUserThread(NtCurrentProcess(),
660 NULL,
661 FALSE,
662 0,
663 0,
664 0,
665 ThreadHandler,
666 NULL,
667 &hThread,
668 &ClientId);
669 if (!NT_SUCCESS(Status))
670 {
671 /* Fail */
672 CsrDeallocateThread(CsrThread);
673 CsrReleaseProcessLock();
674 return Status;
675 }
676
677 /* Setup the Thread Object */
678 CsrThread->ThreadHandle = hThread;
679 CsrThread->ClientId = ClientId;
680 CsrThread->Flags = Flags;
681
682 /* Insert it into the Thread List */
683 InsertHeadList(&CsrRootProcess->ThreadList, &CsrThread->Link);
684
685 /* Increase the thread count */
686 CsrRootProcess->ThreadCount++;
687
688 /* Return */
689 CsrReleaseProcessLock();
690 return Status;
691 }
692
693 /*++
694 * @name CsrDestroyThread
695 * @implemented NT4
696 *
697 * The CsrDestroyThread routine destroys the CSR Thread corresponding to
698 * a given Thread ID.
699 *
700 * @param Cid
701 * Pointer to the Client ID Structure corresponding to the CSR
702 * Thread which is about to be destroyed.
703 *
704 * @return STATUS_SUCCESS in case of success, STATUS_THREAD_IS_TERMINATING
705 * if the CSR Thread is already terminating.
706 *
707 * @remarks None.
708 *
709 *--*/
710 NTSTATUS
711 NTAPI
712 CsrDestroyThread(IN PCLIENT_ID Cid)
713 {
714 CLIENT_ID ClientId = *Cid;
715 PCSR_THREAD CsrThread;
716 PCSR_PROCESS CsrProcess;
717
718 /* Acquire lock */
719 CsrAcquireProcessLock();
720
721 /* Find the thread */
722 CsrThread = CsrLocateThreadByClientId(&CsrProcess,
723 &ClientId);
724
725 /* Make sure we got one back, and that it's not already gone */
726 if (!CsrThread || CsrThread->Flags & CsrThreadTerminated)
727 {
728 /* Release the lock and return failure */
729 CsrReleaseProcessLock();
730 return STATUS_THREAD_IS_TERMINATING;
731 }
732
733 /* Set the terminated flag */
734 CsrThread->Flags |= CsrThreadTerminated;
735
736 /* Acquire the Wait Lock */
737 CsrAcquireWaitLock();
738
739 /* Do we have an active wait block? */
740 if (CsrThread->WaitBlock)
741 {
742 /* Notify waiters of termination */
743 CsrNotifyWaitBlock(CsrThread->WaitBlock,
744 NULL,
745 NULL,
746 NULL,
747 CsrProcessTerminating,
748 TRUE);
749 }
750
751 /* Release the Wait Lock */
752 CsrReleaseWaitLock();
753
754 /* Dereference the thread */
755 CsrLockedDereferenceThread(CsrThread);
756
757 /* Release the Process Lock and return success */
758 CsrReleaseProcessLock();
759 return STATUS_SUCCESS;
760 }
761
762 /*++
763 * @name CsrImpersonateClient
764 * @implemented NT4
765 *
766 * The CsrImpersonateClient will impersonate the given CSR Thread.
767 *
768 * @param CsrThread
769 * Pointer to the CSR Thread to impersonate.
770 *
771 * @return TRUE if impersionation suceeded, false otherwise.
772 *
773 * @remarks Impersonation can be recursive.
774 *
775 *--*/
776 BOOLEAN
777 NTAPI
778 CsrImpersonateClient(IN PCSR_THREAD CsrThread)
779 {
780 NTSTATUS Status;
781 PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
782
783 /* Use the current thread if none given */
784 if (!CsrThread) CsrThread = CurrentThread;
785
786 /* Still no thread, something is wrong */
787 if (!CsrThread)
788 {
789 /* Failure */
790 return FALSE;
791 }
792
793 /* Make the call */
794 Status = NtImpersonateThread(NtCurrentThread(),
795 CsrThread->ThreadHandle,
796 &CsrSecurityQos);
797
798 if (!NT_SUCCESS(Status))
799 {
800 /* Failure */
801 return FALSE;
802 }
803
804 /* Increase the impersonation count for the current thread */
805 if (CurrentThread) ++CurrentThread->ImpersonationCount;
806
807 /* Return Success */
808 return TRUE;
809 }
810
811 /*++
812 * @name CsrRevertToSelf
813 * @implemented NT4
814 *
815 * The CsrRevertToSelf routine will attempt to remove an active impersonation.
816 *
817 * @param None.
818 *
819 * @return TRUE if the reversion was succesful, false otherwise.
820 *
821 * @remarks Impersonation can be recursive; as such, the impersonation token
822 * will only be deleted once the CSR Thread's impersonaton count
823 * has reached zero.
824 *
825 *--*/
826 BOOLEAN
827 NTAPI
828 CsrRevertToSelf(VOID)
829 {
830 NTSTATUS Status;
831 PCSR_THREAD CurrentThread = NtCurrentTeb()->CsrClientThread;
832 HANDLE ImpersonationToken = NULL;
833
834 /* Check if we have a Current Thread */
835 if (CurrentThread)
836 {
837 /* Make sure impersonation is on */
838 if (!CurrentThread->ImpersonationCount)
839 {
840 return FALSE;
841 }
842 else if (--CurrentThread->ImpersonationCount > 0)
843 {
844 /* Success; impersonation count decreased but still not zero */
845 return TRUE;
846 }
847 }
848
849 /* Impersonation has been totally removed, revert to ourselves */
850 Status = NtSetInformationThread(NtCurrentThread(),
851 ThreadImpersonationToken,
852 &ImpersonationToken,
853 sizeof(HANDLE));
854
855 /* Return TRUE or FALSE */
856 return NT_SUCCESS(Status);
857 }
858
859 /*++
860 * @name CsrLockThreadByClientId
861 * @implemented NT4
862 *
863 * The CsrLockThreadByClientId routine locks the CSR Thread corresponding
864 * to the given Thread ID and optionally returns it.
865 *
866 * @param Tid
867 * Thread ID corresponding to the CSR Thread which will be locked.
868 *
869 * @param CsrThread
870 * Optional pointer to a CSR Thread pointer which will hold the
871 * CSR Thread corresponding to the given Thread ID.
872 *
873 * @return STATUS_SUCCESS in case of success, STATUS_UNSUCCESSFUL
874 * othwerwise.
875 *
876 * @remarks Locking a CSR Thread is defined as acquiring an extra
877 * reference to it and returning with the Process Lock held.
878 *
879 *--*/
880 NTSTATUS
881 NTAPI
882 CsrLockThreadByClientId(IN HANDLE Tid,
883 OUT PCSR_THREAD *CsrThread OPTIONAL)
884 {
885 PLIST_ENTRY ListHead, NextEntry;
886 PCSR_THREAD CurrentThread = NULL;
887 NTSTATUS Status = STATUS_UNSUCCESSFUL;
888 ULONG i;
889
890 /* Acquire the lock */
891 CsrAcquireProcessLock();
892
893 /* Convert to Hash */
894 i = CsrHashThread(Tid);
895
896 /* Setup the List Pointers */
897 ListHead = &CsrThreadHashTable[i];
898 NextEntry = ListHead;
899
900 /* Start Loop */
901 while (NextEntry != ListHead)
902 {
903 /* Get the Process */
904 CurrentThread = CONTAINING_RECORD(NextEntry, CSR_THREAD, HashLinks);
905
906 /* Check for PID Match */
907 if ((CurrentThread->ClientId.UniqueThread == Tid) &&
908 !(CurrentThread->Flags & CsrThreadTerminated))
909 {
910 /* Get out of here with success */
911 Status = STATUS_SUCCESS;
912 break;
913 }
914
915 /* Next entry */
916 NextEntry = NextEntry->Flink;
917 }
918
919 /* Did the loop find something? */
920 if (NT_SUCCESS(Status))
921 {
922 /* Reference the found thread */
923 CurrentThread->ReferenceCount++;
924 }
925 else
926 {
927 /* Nothing found, release the lock */
928 CsrReleaseProcessLock();
929 }
930
931 /* Return the status and thread */
932 if (CsrThread) *CsrThread = CurrentThread;
933 return Status;
934 }
935
936 /*++
937 * @name CsrReferenceThread
938 * @implemented NT4
939 *
940 * The CsrReferenceThread routine increases the active reference count of
941 * a CSR Thread.
942 *
943 * @param CsrThread
944 * Pointer to the CSR Thread whose reference count will be increased.
945 *
946 * @return None.
947 *
948 * @remarks Do not use this routine if the Process Lock is already held.
949 *
950 *--*/
951 VOID
952 NTAPI
953 CsrReferenceThread(PCSR_THREAD CsrThread)
954 {
955 /* Acquire process lock */
956 CsrAcquireProcessLock();
957
958 /* Increment reference count */
959 CsrThread->ReferenceCount++;
960
961 /* Release the lock */
962 CsrReleaseProcessLock();
963 }
964
965 /*++
966 * @name CsrUnlockThread
967 * @implemented NT4
968 *
969 * The CsrUnlockThread undoes a previous CsrLockThreadByClientId operation.
970 *
971 * @param CsrThread
972 * Pointer to a previously locked CSR Thread.
973 *
974 * @return STATUS_SUCCESS.
975 *
976 * @remarks This routine must be called with the Process Lock held.
977 *
978 *--*/
979 NTSTATUS
980 NTAPI
981 CsrUnlockThread(PCSR_THREAD CsrThread)
982 {
983 /* Dereference the Thread */
984 CsrLockedDereferenceThread(CsrThread);
985
986 /* Release the lock and return */
987 CsrReleaseProcessLock();
988 return STATUS_SUCCESS;
989 }
990
991 /* EOF */