Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

918 lines
23 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. psenum.c
  5. Abstract:
  6. This module enumerates the actve processes in the system
  7. Author:
  8. Neill clift (NeillC) 23-Mar-2000
  9. Revision History:
  10. --*/
  11. #include "psp.h"
  12. #ifdef ALLOC_PRAGMA
  13. #pragma alloc_text(PAGE, PsEnumProcesses)
  14. #pragma alloc_text(PAGE, PsGetNextProcess)
  15. #pragma alloc_text(PAGE, PsQuitNextProcess)
  16. #pragma alloc_text(PAGE, PsEnumProcessThreads)
  17. #pragma alloc_text(PAGE, PsGetNextProcessThread)
  18. #pragma alloc_text(PAGE, PsQuitNextProcessThread)
  19. #pragma alloc_text(PAGE, PsGetNextJob)
  20. #pragma alloc_text(PAGE, PsGetNextJobProcess)
  21. #pragma alloc_text(PAGE, PsQuitNextJob)
  22. #pragma alloc_text(PAGE, PsQuitNextJobProcess)
  23. #pragma alloc_text(PAGE, PspGetNextJobProcess)
  24. #pragma alloc_text(PAGE, PspQuitNextJobProcess)
  25. #pragma alloc_text(PAGE, NtGetNextProcess)
  26. #pragma alloc_text(PAGE, NtGetNextThread)
  27. #endif
  28. NTSTATUS
  29. PsEnumProcesses (
  30. IN PROCESS_ENUM_ROUTINE CallBack,
  31. IN PVOID Context
  32. )
  33. /*++
  34. Routine Description:
  35. This function calls the callback routine for each active process in the system.
  36. Process objects in the process of being deleted are skipped.
  37. Returning anything but a success code from the callback routine terminates the enumeration at that point.
  38. Processes may be referenced and used later safely.
  39. Arguments:
  40. CallBack - Routine to be called with its first parameter the enumerated process
  41. Return Value:
  42. NTSTATUS - Status of call
  43. --*/
  44. {
  45. PLIST_ENTRY ListEntry;
  46. PEPROCESS Process, NewProcess;
  47. PETHREAD CurrentThread;
  48. NTSTATUS Status;
  49. Process = NULL;
  50. CurrentThread = PsGetCurrentThread ();
  51. PspLockProcessList (CurrentThread);
  52. for (ListEntry = PsActiveProcessHead.Flink;
  53. ListEntry != &PsActiveProcessHead;
  54. ListEntry = ListEntry->Flink) {
  55. NewProcess = CONTAINING_RECORD (ListEntry, EPROCESS, ActiveProcessLinks);
  56. if (ObReferenceObjectSafe (NewProcess)) {
  57. PspUnlockProcessList (CurrentThread);
  58. if (Process != NULL) {
  59. ObDereferenceObject (Process);
  60. }
  61. Process = NewProcess;
  62. Status = CallBack (Process, Context);
  63. if (!NT_SUCCESS (Status)) {
  64. ObDereferenceObject (Process);
  65. return Status;
  66. }
  67. PspLockProcessList (CurrentThread);
  68. }
  69. }
  70. PspUnlockProcessList (CurrentThread);
  71. if (Process != NULL) {
  72. ObDereferenceObject (Process);
  73. }
  74. return STATUS_SUCCESS;
  75. }
  76. PEPROCESS
  77. PsGetNextProcess (
  78. IN PEPROCESS Process
  79. )
  80. /*++
  81. Routine Description:
  82. This function allows code to enumerate all the active processes in the system.
  83. The first process (if Process is NULL) or subsequent process (if process not NULL) is returned on
  84. each call.
  85. If process is not NULL then this process must have previously been obtained by a call to PsGetNextProcess.
  86. Enumeration may be terminated early by calling PsQuitNextProcess on the last non-NULL process
  87. returned by PsGetNextProcess.
  88. Processes may be referenced and used later safely.
  89. For example, to enumerate all system processes in a loop use this code fragment:
  90. for (Process = PsGetNextProcess (NULL);
  91. Process != NULL;
  92. Process = PsGetNextProcess (Process)) {
  93. ...
  94. ...
  95. //
  96. // Early terminating conditions are handled like this:
  97. //
  98. if (NeedToBreakOutEarly) {
  99. PsQuitNextProcess (Process);
  100. break;
  101. }
  102. }
  103. Arguments:
  104. Process - Process to get the next process from or NULL for the first process
  105. Return Value:
  106. PEPROCESS - Next process or NULL if no more processes available
  107. --*/
  108. {
  109. PEPROCESS NewProcess = NULL;
  110. PETHREAD CurrentThread;
  111. PLIST_ENTRY ListEntry;
  112. CurrentThread = PsGetCurrentThread ();
  113. PspLockProcessList (CurrentThread);
  114. for (ListEntry = (Process == NULL) ? PsActiveProcessHead.Flink : Process->ActiveProcessLinks.Flink;
  115. ListEntry != &PsActiveProcessHead;
  116. ListEntry = ListEntry->Flink) {
  117. NewProcess = CONTAINING_RECORD (ListEntry, EPROCESS, ActiveProcessLinks);
  118. //
  119. // Processes are removed from this list during process objected deletion (object reference count goes
  120. // to zero). To prevent double deletion of the process we need to do a safe reference here.
  121. //
  122. if (ObReferenceObjectSafe (NewProcess)) {
  123. break;
  124. }
  125. NewProcess = NULL;
  126. }
  127. PspUnlockProcessList (CurrentThread);
  128. if (Process != NULL) {
  129. ObDereferenceObject (Process);
  130. }
  131. return NewProcess;
  132. }
  133. VOID
  134. PsQuitNextProcess (
  135. IN PEPROCESS Process
  136. )
  137. /*++
  138. Routine Description:
  139. This function is used to terminate early a process enumeration using PsGetNextProcess
  140. Arguments:
  141. Process - Non-NULL process previously obtained by a call to PsGetNextProcess.
  142. Return Value:
  143. None
  144. --*/
  145. {
  146. ObDereferenceObject (Process);
  147. }
  148. PETHREAD
  149. PsGetNextProcessThread (
  150. IN PEPROCESS Process,
  151. IN PETHREAD Thread
  152. )
  153. /*++
  154. Routine Description:
  155. This function is used to enumerate the threads in a process.
  156. Arguments:
  157. Process - Process to enumerate
  158. Thread - Thread to start enumeration from. This must have been obtained from previous call to
  159. PsGetNextProcessThread. If NULL enumeration starts at the first non-terminating thread in the process.
  160. Return Value:
  161. PETHREAD - Pointer to a non-terminated process thread or a NULL if there are non. This thread must be passed
  162. either to another call to PsGetNextProcessThread or PsQuitNextProcessThread.
  163. --*/
  164. {
  165. PLIST_ENTRY ListEntry;
  166. PETHREAD NewThread, CurrentThread;
  167. PAGED_CODE ();
  168. CurrentThread = PsGetCurrentThread ();
  169. PspLockProcessShared (Process, CurrentThread);
  170. for (ListEntry = (Thread == NULL) ? Process->ThreadListHead.Flink : Thread->ThreadListEntry.Flink;
  171. ;
  172. ListEntry = ListEntry->Flink) {
  173. if (ListEntry != &Process->ThreadListHead) {
  174. NewThread = CONTAINING_RECORD (ListEntry, ETHREAD, ThreadListEntry);
  175. //
  176. // Don't reference a thread thats in its delete routine
  177. //
  178. if (ObReferenceObjectSafe (NewThread)) {
  179. break;
  180. }
  181. } else {
  182. NewThread = NULL;
  183. break;
  184. }
  185. }
  186. PspUnlockProcessShared (Process, CurrentThread);
  187. if (Thread != NULL) {
  188. ObDereferenceObject (Thread);
  189. }
  190. return NewThread;
  191. }
  192. VOID
  193. PsQuitNextProcessThread (
  194. IN PETHREAD Thread
  195. )
  196. /*++
  197. Routine Description:
  198. This function quits thread enumeration early.
  199. Arguments:
  200. Thread - Thread obtained from a call to PsGetNextProcessThread
  201. Return Value:
  202. None.
  203. --*/
  204. {
  205. ObDereferenceObject (Thread);
  206. }
  207. NTSTATUS
  208. PsEnumProcessThreads (
  209. IN PEPROCESS Process,
  210. IN THREAD_ENUM_ROUTINE CallBack,
  211. IN PVOID Context
  212. )
  213. /*++
  214. Routine Description:
  215. This function calls the callback routine for each active thread in the process.
  216. Thread objects in the process of being deleted are skipped.
  217. Returning anything but a success code from the callback routine terminates the enumeration at that point.
  218. Thread may be referenced and used later safely.
  219. Arguments:
  220. CallBack - Routine to be called with its first parameter the enumerated process
  221. Return Value:
  222. NTSTATUS - Status of call
  223. --*/
  224. {
  225. NTSTATUS Status;
  226. PETHREAD Thread;
  227. Status = STATUS_SUCCESS;
  228. for (Thread = PsGetNextProcessThread (Process, NULL);
  229. Thread != NULL;
  230. Thread = PsGetNextProcessThread (Process, Thread)) {
  231. Status = CallBack (Process, Thread, Context);
  232. if (!NT_SUCCESS (Status)) {
  233. PsQuitNextProcessThread (Thread);
  234. break;
  235. }
  236. }
  237. return Status;
  238. }
  239. PEJOB
  240. PsGetNextJob (
  241. IN PEJOB Job
  242. )
  243. /*++
  244. Routine Description:
  245. This function allows code to enumerate all the active jobs in the system.
  246. The first job (if Job is NULL) or subsequent jobs (if Job not NULL) is returned on
  247. each call.
  248. If Job is not NULL then this job must have previously been obtained by a call to PsGetNextJob.
  249. Enumeration may be terminated early by calling PsQuitNextJob on the last non-NULL job
  250. returned by PsGetNextJob.
  251. Jobs may be referenced and used later safely.
  252. For example, to enumerate all system jobs in a loop use this code fragment:
  253. for (Job = PsGetNextJob (NULL);
  254. Job != NULL;
  255. Job = PsGetNextJob (Job)) {
  256. ...
  257. ...
  258. //
  259. // Early terminating conditions are handled like this:
  260. //
  261. if (NeedToBreakOutEarly) {
  262. PsQuitNextJob (Job);
  263. break;
  264. }
  265. }
  266. Arguments:
  267. Job - Job from a previous call to PsGetNextJob or NULL for the first job in the system
  268. Return Value:
  269. PEJOB - Next job in the system or NULL if none available.
  270. --*/
  271. {
  272. PEJOB NewJob = NULL;
  273. PLIST_ENTRY ListEntry;
  274. PETHREAD CurrentThread;
  275. CurrentThread = PsGetCurrentThread ();
  276. PspLockJobListShared (CurrentThread);
  277. for (ListEntry = (Job == NULL) ? PspJobList.Flink : Job->JobLinks.Flink;
  278. ListEntry != &PspJobList;
  279. ListEntry = ListEntry->Flink) {
  280. NewJob = CONTAINING_RECORD (ListEntry, EJOB, JobLinks);
  281. //
  282. // Jobs are removed from this list during job objected deletion (object reference count goes
  283. // to zero). To prevent double deletion of the job we need to do a safe reference here.
  284. //
  285. if (ObReferenceObjectSafe (NewJob)) {
  286. break;
  287. }
  288. NewJob = NULL;
  289. }
  290. PspUnlockJobListShared (CurrentThread);
  291. if (Job != NULL) {
  292. ObDereferenceObject (Job);
  293. }
  294. return NewJob;
  295. }
  296. VOID
  297. PsQuitNextJob (
  298. IN PEJOB Job
  299. )
  300. /*++
  301. Routine Description:
  302. This function is used to terminate early a job enumeration using PsGetNextJob
  303. Arguments:
  304. Job - Non-NULL job previously obtained by a call to PsGetNextJob.
  305. Return Value:
  306. None
  307. --*/
  308. {
  309. ObDereferenceObject (Job);
  310. }
  311. PEPROCESS
  312. PsGetNextJobProcess (
  313. IN PEJOB Job,
  314. IN PEPROCESS Process
  315. )
  316. /*++
  317. Routine Description:
  318. This function is used to enumerate the processes in a job.
  319. Arguments:
  320. Job - Job to Enumerate
  321. Process - Process to start enumeration from. This must have been obtained from previous call to
  322. PsGetNextJobProcess. If NULL enumeration starts at the first non-terminating process in the Job.
  323. Return Value:
  324. PEPROCESS - Pointer to a non-terminated process or a NULL if there are non. This process must be passed
  325. either to another call to PsGetNextJobProcess or PsQuitNextJobProcess.
  326. --*/
  327. {
  328. PLIST_ENTRY ListEntry;
  329. PEPROCESS NewProcess;
  330. PETHREAD CurrentThread;
  331. PAGED_CODE ();
  332. CurrentThread = PsGetCurrentThread ();
  333. KeEnterCriticalRegionThread (&CurrentThread->Tcb);
  334. ExAcquireResourceExclusiveLite (&Job->JobLock, TRUE);
  335. for (ListEntry = (Process == NULL) ? Job->ProcessListHead.Flink : Process->JobLinks.Flink;
  336. ;
  337. ListEntry = ListEntry->Flink) {
  338. if (ListEntry != &Job->ProcessListHead) {
  339. NewProcess = CONTAINING_RECORD (ListEntry, EPROCESS, JobLinks);
  340. //
  341. // Don't reference a process thats in its delete routine
  342. //
  343. if (ObReferenceObjectSafe (NewProcess)) {
  344. break;
  345. }
  346. } else {
  347. NewProcess = NULL;
  348. break;
  349. }
  350. }
  351. ExReleaseResourceLite (&Job->JobLock);
  352. KeLeaveCriticalRegionThread (&CurrentThread->Tcb);
  353. if (Process != NULL) {
  354. ObDereferenceObject (Process);
  355. }
  356. return NewProcess;
  357. }
  358. VOID
  359. PsQuitNextJobProcess (
  360. IN PEPROCESS Process
  361. )
  362. /*++
  363. Routine Description:
  364. This function quits job process enumeration early.
  365. Arguments:
  366. Process - Process obtained from a call to PsGetNextJobProcess
  367. Return Value:
  368. None.
  369. --*/
  370. {
  371. ObDereferenceObject (Process);
  372. }
  373. PEPROCESS
  374. PspGetNextJobProcess (
  375. IN PEJOB Job,
  376. IN PEPROCESS Process
  377. )
  378. /*++
  379. Routine Description:
  380. This function is used to enumerate the processes in a job with the job lock held.
  381. Arguments:
  382. Job - Job to Enumerate
  383. Process - Process to start enumeration from. This must have been obtained from previous call to
  384. PsGetNextJobProcess. If NULL enumeration starts at the first non-terminating process in the Job.
  385. Return Value:
  386. PEPROCESS - Pointer to a non-terminated process or a NULL if there are non. This process must be passed
  387. either to another call to PsGetNextJobProcess or PsQuitNextJobProcess.
  388. --*/
  389. {
  390. PLIST_ENTRY ListEntry;
  391. PEPROCESS NewProcess;
  392. PAGED_CODE ();
  393. for (ListEntry = (Process == NULL) ? Job->ProcessListHead.Flink : Process->JobLinks.Flink;
  394. ;
  395. ListEntry = ListEntry->Flink) {
  396. if (ListEntry != &Job->ProcessListHead) {
  397. NewProcess = CONTAINING_RECORD (ListEntry, EPROCESS, JobLinks);
  398. //
  399. // Don't reference a process thats in its delete routine
  400. //
  401. if (ObReferenceObjectSafe (NewProcess)) {
  402. break;
  403. }
  404. } else {
  405. NewProcess = NULL;
  406. break;
  407. }
  408. }
  409. if (Process != NULL) {
  410. ObDereferenceObjectDeferDelete (Process);
  411. }
  412. return NewProcess;
  413. }
  414. VOID
  415. PspQuitNextJobProcess (
  416. IN PEPROCESS Process
  417. )
  418. /*++
  419. Routine Description:
  420. This function quits job process enumeration early.
  421. Arguments:
  422. Process - Process obtained from a call to PsGetNextJobProcess
  423. Return Value:
  424. None.
  425. --*/
  426. {
  427. ObDereferenceObjectDeferDelete (Process);
  428. }
  429. NTSTATUS
  430. NtGetNextProcess (
  431. IN HANDLE ProcessHandle,
  432. IN ACCESS_MASK DesiredAccess,
  433. IN ULONG HandleAttributes,
  434. IN ULONG Flags,
  435. OUT PHANDLE NewProcessHandle
  436. )
  437. /*++
  438. Routine Description:
  439. This function gets the next for first process in the list of all processes in the system
  440. Arguments:
  441. ProcessHandle - Process obtained from a previous call to NtGetNextProcess or NULL for the first process
  442. DesiredAccess - Access requested for process handle
  443. HandleAttributes - Handle attributes requested.
  444. Flags - Flags for the operation
  445. NewProcessHandle - Pointer to a handle value that is returned on sucess
  446. Return Value:
  447. NTSTATUS - Status of operation.
  448. --*/
  449. {
  450. KPROCESSOR_MODE PreviousMode;
  451. PEPROCESS Process, NewProcess;
  452. NTSTATUS Status;
  453. ACCESS_STATE AccessState;
  454. AUX_ACCESS_DATA AuxData;
  455. HANDLE Handle;
  456. PAGED_CODE ();
  457. PreviousMode = KeGetPreviousMode ();
  458. //
  459. // Sanitize handle attributes
  460. //
  461. HandleAttributes = ObSanitizeHandleAttributes (HandleAttributes, PreviousMode);
  462. //
  463. // Validate pointer arguments
  464. //
  465. try {
  466. if (PreviousMode != KernelMode) {
  467. ProbeForWriteHandle (NewProcessHandle);
  468. }
  469. *NewProcessHandle = NULL;
  470. } except (ExSystemExceptionFilter ()) {
  471. return GetExceptionCode ();
  472. }
  473. //
  474. // Check for inclusion of reserved flags and reject the call if present
  475. //
  476. if (Flags != 0) {
  477. return STATUS_INVALID_PARAMETER;
  478. }
  479. if (ProcessHandle == NULL) {
  480. Process = NULL;
  481. } else {
  482. Status = ObReferenceObjectByHandle (ProcessHandle,
  483. 0,
  484. PsProcessType,
  485. PreviousMode,
  486. &Process,
  487. NULL);
  488. if (!NT_SUCCESS (Status)) {
  489. return Status;
  490. }
  491. }
  492. NewProcess = PsGetNextProcess (Process);
  493. if (NewProcess == NULL) {
  494. return STATUS_NO_MORE_ENTRIES;
  495. }
  496. Status = SeCreateAccessState (&AccessState,
  497. &AuxData,
  498. DesiredAccess,
  499. &PsProcessType->TypeInfo.GenericMapping);
  500. if (!NT_SUCCESS (Status)) {
  501. ObDereferenceObject (NewProcess);
  502. return Status;
  503. }
  504. if (SeSinglePrivilegeCheck (SeDebugPrivilege, PreviousMode)) {
  505. if (AccessState.RemainingDesiredAccess & MAXIMUM_ALLOWED) {
  506. AccessState.PreviouslyGrantedAccess |= PROCESS_ALL_ACCESS;
  507. } else {
  508. AccessState.PreviouslyGrantedAccess |= AccessState.RemainingDesiredAccess;
  509. }
  510. AccessState.RemainingDesiredAccess = 0;
  511. }
  512. while (1) {
  513. if (NewProcess->GrantedAccess != 0) {
  514. Status = ObOpenObjectByPointer (NewProcess,
  515. HandleAttributes,
  516. &AccessState,
  517. 0,
  518. PsProcessType,
  519. PreviousMode,
  520. &Handle);
  521. if (NT_SUCCESS (Status)) {
  522. try {
  523. *NewProcessHandle = Handle;
  524. } except (ExSystemExceptionFilter ()) {
  525. Status = GetExceptionCode ();
  526. }
  527. break;
  528. }
  529. if (Status != STATUS_ACCESS_DENIED) {
  530. break;
  531. }
  532. }
  533. NewProcess = PsGetNextProcess (NewProcess);
  534. if (NewProcess == NULL) {
  535. Status = STATUS_NO_MORE_ENTRIES;
  536. break;
  537. }
  538. }
  539. SeDeleteAccessState (&AccessState);
  540. if (NewProcess != NULL) {
  541. ObDereferenceObject (NewProcess);
  542. }
  543. return Status;
  544. }
  545. NTSTATUS
  546. NtGetNextThread (
  547. IN HANDLE ProcessHandle,
  548. IN HANDLE ThreadHandle,
  549. IN ACCESS_MASK DesiredAccess,
  550. IN ULONG HandleAttributes,
  551. IN ULONG Flags,
  552. OUT PHANDLE NewThreadHandle
  553. )
  554. /*++
  555. Routine Description:
  556. This function gets the next for first thread in a process
  557. Arguments:
  558. ProcessHandle - Process that is being enumerated
  559. ThreadHandle - Last thread returned by the enumeration routine or NULL if the first is required
  560. DesiredAccess - Access requested for thread handle
  561. HandleAttributes - Handle attributes requested.
  562. Flags - Flags for the operation
  563. NewThreadHandle - Pointer to a handle value that is returned on sucess
  564. Return Value:
  565. NTSTATUS - Status of operation.
  566. --*/
  567. {
  568. KPROCESSOR_MODE PreviousMode;
  569. PEPROCESS Process;
  570. PETHREAD Thread, NewThread;
  571. NTSTATUS Status;
  572. ACCESS_STATE AccessState;
  573. AUX_ACCESS_DATA AuxData;
  574. HANDLE Handle;
  575. PAGED_CODE ();
  576. PreviousMode = KeGetPreviousMode ();
  577. //
  578. // Sanitize handle attributes
  579. //
  580. HandleAttributes = ObSanitizeHandleAttributes (HandleAttributes, PreviousMode);
  581. //
  582. // Validate pointer arguments
  583. //
  584. try {
  585. if (PreviousMode != KernelMode) {
  586. ProbeForWriteHandle (NewThreadHandle);
  587. }
  588. *NewThreadHandle = NULL;
  589. } except (ExSystemExceptionFilter ()) {
  590. return GetExceptionCode ();
  591. }
  592. //
  593. // Check for inclusion of reserved flags and reject the call if present
  594. //
  595. if (Flags != 0) {
  596. return STATUS_INVALID_PARAMETER;
  597. }
  598. Status = ObReferenceObjectByHandle (ProcessHandle,
  599. PROCESS_QUERY_INFORMATION,
  600. PsProcessType,
  601. PreviousMode,
  602. &Process,
  603. NULL);
  604. if (!NT_SUCCESS (Status)) {
  605. return Status;
  606. }
  607. if (ThreadHandle == NULL) {
  608. Thread = NULL;
  609. } else {
  610. Status = ObReferenceObjectByHandle (ThreadHandle,
  611. 0,
  612. PsProcessType,
  613. PreviousMode,
  614. &Thread,
  615. NULL);
  616. if (!NT_SUCCESS (Status)) {
  617. ObDereferenceObject (Process);
  618. return Status;
  619. }
  620. //
  621. // Make sure
  622. //
  623. if (THREAD_TO_PROCESS (Thread) != Process) {
  624. ObDereferenceObject (Thread);
  625. ObDereferenceObject (Process);
  626. return STATUS_INVALID_PARAMETER;
  627. }
  628. }
  629. NewThread = PsGetNextProcessThread (Process, Thread);
  630. if (NewThread == NULL) {
  631. ObDereferenceObject (Process);
  632. return STATUS_NO_MORE_ENTRIES;
  633. }
  634. Status = SeCreateAccessState (&AccessState,
  635. &AuxData,
  636. DesiredAccess,
  637. &PsProcessType->TypeInfo.GenericMapping);
  638. if (!NT_SUCCESS (Status)) {
  639. ObDereferenceObject (Process);
  640. ObDereferenceObject (NewThread);
  641. return Status;
  642. }
  643. if (SeSinglePrivilegeCheck (SeDebugPrivilege, PreviousMode)) {
  644. if (AccessState.RemainingDesiredAccess & MAXIMUM_ALLOWED) {
  645. AccessState.PreviouslyGrantedAccess |= PROCESS_ALL_ACCESS;
  646. } else {
  647. AccessState.PreviouslyGrantedAccess |= AccessState.RemainingDesiredAccess;
  648. }
  649. AccessState.RemainingDesiredAccess = 0;
  650. }
  651. while (1) {
  652. if (NewThread->GrantedAccess != 0) {
  653. Status = ObOpenObjectByPointer (NewThread,
  654. HandleAttributes,
  655. &AccessState,
  656. 0,
  657. PsThreadType,
  658. PreviousMode,
  659. &Handle);
  660. if (NT_SUCCESS (Status)) {
  661. try {
  662. *NewThreadHandle = Handle;
  663. } except (ExSystemExceptionFilter ()) {
  664. Status = GetExceptionCode ();
  665. }
  666. break;
  667. }
  668. if (Status != STATUS_ACCESS_DENIED) {
  669. break;
  670. }
  671. }
  672. NewThread = PsGetNextProcessThread (Process, NewThread);
  673. if (NewThread == NULL) {
  674. Status = STATUS_NO_MORE_ENTRIES;
  675. break;
  676. }
  677. }
  678. SeDeleteAccessState (&AccessState);
  679. ObDereferenceObject (Process);
  680. if (NewThread != NULL) {
  681. ObDereferenceObject (NewThread);
  682. }
  683. return Status;
  684. }