[SHELL-EXPERIMENTS]
[reactos.git] / ntoskrnl / ps / process.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/ps/process.c
5 * PURPOSE: Process Manager: Process Management
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 * Thomas Weidenmueller (w3seek@reactos.org
8 */
9
10 /* INCLUDES ******************************************************************/
11
12 #include <ntoskrnl.h>
13 #define NDEBUG
14 #include <debug.h>
15
16 /* GLOBALS *******************************************************************/
17
18 extern ULONG PsMinimumWorkingSet, PsMaximumWorkingSet;
19
20 POBJECT_TYPE PsProcessType = NULL;
21
22 LIST_ENTRY PsActiveProcessHead;
23 KGUARDED_MUTEX PspActiveProcessMutex;
24
25 LARGE_INTEGER ShortPsLockDelay;
26
27 ULONG PsRawPrioritySeparation = 0;
28 ULONG PsPrioritySeparation;
29 CHAR PspForegroundQuantum[3];
30
31 /* Fixed quantum table */
32 CHAR PspFixedQuantums[6] =
33 {
34 /* Short quantums */
35 3 * 6, /* Level 1 */
36 3 * 6, /* Level 2 */
37 3 * 6, /* Level 3 */
38
39 /* Long quantums */
40 6 * 6, /* Level 1 */
41 6 * 6, /* Level 2 */
42 6 * 6 /* Level 3 */
43 };
44
45 /* Variable quantum table */
46 CHAR PspVariableQuantums[6] =
47 {
48 /* Short quantums */
49 1 * 6, /* Level 1 */
50 2 * 6, /* Level 2 */
51 3 * 6, /* Level 3 */
52
53 /* Long quantums */
54 2 * 6, /* Level 1 */
55 4 * 6, /* Level 2 */
56 6 * 6 /* Level 3 */
57 };
58
59 /* Priority table */
60 KPRIORITY PspPriorityTable[PROCESS_PRIORITY_CLASS_ABOVE_NORMAL + 1] =
61 {
62 8,
63 4,
64 8,
65 13,
66 24,
67 6,
68 10
69 };
70
71 /* PRIVATE FUNCTIONS *********************************************************/
72
73 PETHREAD
74 NTAPI
75 PsGetNextProcessThread(IN PEPROCESS Process,
76 IN PETHREAD Thread OPTIONAL)
77 {
78 PETHREAD FoundThread = NULL;
79 PLIST_ENTRY ListHead, Entry;
80 PAGED_CODE();
81 PSTRACE(PS_PROCESS_DEBUG,
82 "Process: %p Thread: %p\n", Process, Thread);
83
84 /* Lock the process */
85 KeEnterCriticalRegion();
86 ExAcquirePushLockShared(&Process->ProcessLock);
87
88 /* Check if we're already starting somewhere */
89 if (Thread)
90 {
91 /* Start where we left off */
92 Entry = Thread->ThreadListEntry.Flink;
93 }
94 else
95 {
96 /* Start at the beginning */
97 Entry = Process->ThreadListHead.Flink;
98 }
99
100 /* Set the list head and start looping */
101 ListHead = &Process->ThreadListHead;
102 while (ListHead != Entry)
103 {
104 /* Get the Thread */
105 FoundThread = CONTAINING_RECORD(Entry, ETHREAD, ThreadListEntry);
106
107 /* Safe reference the thread */
108 if (ObReferenceObjectSafe(FoundThread)) break;
109
110 /* Nothing found, keep looping */
111 FoundThread = NULL;
112 Entry = Entry->Flink;
113 }
114
115 /* Unlock the process */
116 ExReleasePushLockShared(&Process->ProcessLock);
117 KeLeaveCriticalRegion();
118
119 /* Check if we had a starting thread, and dereference it */
120 if (Thread) ObDereferenceObject(Thread);
121
122 /* Return what we found */
123 return FoundThread;
124 }
125
126 PEPROCESS
127 NTAPI
128 PsGetNextProcess(IN PEPROCESS OldProcess)
129 {
130 PLIST_ENTRY Entry;
131 PEPROCESS FoundProcess = NULL;
132 PAGED_CODE();
133 PSTRACE(PS_PROCESS_DEBUG, "Process: %p\n", OldProcess);
134
135 /* Acquire the Active Process Lock */
136 KeAcquireGuardedMutex(&PspActiveProcessMutex);
137
138 /* Check if we're already starting somewhere */
139 if (OldProcess)
140 {
141 /* Start where we left off */
142 Entry = OldProcess->ActiveProcessLinks.Flink;
143 }
144 else
145 {
146 /* Start at the beginning */
147 Entry = PsActiveProcessHead.Flink;
148 }
149
150 /* Loop the process list */
151 while (Entry != &PsActiveProcessHead)
152 {
153 /* Get the process */
154 FoundProcess = CONTAINING_RECORD(Entry, EPROCESS, ActiveProcessLinks);
155
156 /* Reference the process */
157 if (ObReferenceObjectSafe(FoundProcess)) break;
158
159 /* Nothing found, keep trying */
160 FoundProcess = NULL;
161 Entry = Entry->Flink;
162 }
163
164 /* Release the lock */
165 KeReleaseGuardedMutex(&PspActiveProcessMutex);
166
167 /* Dereference the Process we had referenced earlier */
168 if (OldProcess) ObDereferenceObject(OldProcess);
169 return FoundProcess;
170 }
171
172 KPRIORITY
173 NTAPI
174 PspComputeQuantumAndPriority(IN PEPROCESS Process,
175 IN PSPROCESSPRIORITYMODE Mode,
176 OUT PUCHAR Quantum)
177 {
178 ULONG i;
179 UCHAR LocalQuantum, MemoryPriority;
180 PAGED_CODE();
181 PSTRACE(PS_PROCESS_DEBUG, "Process: %p Mode: %lx\n", Process, Mode);
182
183 /* Check if this is a foreground process */
184 if (Mode == PsProcessPriorityForeground)
185 {
186 /* Set the memory priority and use priority separation */
187 MemoryPriority = MEMORY_PRIORITY_FOREGROUND;
188 i = PsPrioritySeparation;
189 }
190 else
191 {
192 /* Set the background memory priority and no separation */
193 MemoryPriority = MEMORY_PRIORITY_BACKGROUND;
194 i = 0;
195 }
196
197 /* Make sure that the process mode isn't spinning */
198 if (Mode != PsProcessPrioritySpinning)
199 {
200 /* Set the priority */
201 MmSetMemoryPriorityProcess(Process, MemoryPriority);
202 }
203
204 /* Make sure that the process isn't idle */
205 if (Process->PriorityClass != PROCESS_PRIORITY_CLASS_IDLE)
206 {
207 /* Does the process have a job? */
208 if ((Process->Job) && (PspUseJobSchedulingClasses))
209 {
210 /* Use job quantum */
211 LocalQuantum = PspJobSchedulingClasses[Process->Job->
212 SchedulingClass];
213 }
214 else
215 {
216 /* Use calculated quantum */
217 LocalQuantum = PspForegroundQuantum[i];
218 }
219 }
220 else
221 {
222 /* Process is idle, use default quantum */
223 LocalQuantum = 6;
224 }
225
226 /* Return quantum to caller */
227 *Quantum = LocalQuantum;
228
229 /* Return priority */
230 return PspPriorityTable[Process->PriorityClass];
231 }
232
233 VOID
234 NTAPI
235 PsChangeQuantumTable(IN BOOLEAN Immediate,
236 IN ULONG PrioritySeparation)
237 {
238 PEPROCESS Process = NULL;
239 ULONG i;
240 UCHAR Quantum;
241 PCHAR QuantumTable;
242 PAGED_CODE();
243 PSTRACE(PS_PROCESS_DEBUG,
244 "%lx PrioritySeparation: %lx\n", Immediate, PrioritySeparation);
245
246 /* Write the current priority separation */
247 PsPrioritySeparation = PspPrioritySeparationFromMask(PrioritySeparation);
248
249 /* Normalize it if it was too high */
250 if (PsPrioritySeparation == 3) PsPrioritySeparation = 2;
251
252 /* Get the quantum table to use */
253 if (PspQuantumTypeFromMask(PrioritySeparation) == PSP_VARIABLE_QUANTUMS)
254 {
255 /* Use a variable table */
256 QuantumTable = PspVariableQuantums;
257 }
258 else
259 {
260 /* Use fixed table */
261 QuantumTable = PspFixedQuantums;
262 }
263
264 /* Now check if we should use long or short */
265 if (PspQuantumLengthFromMask(PrioritySeparation) == PSP_LONG_QUANTUMS)
266 {
267 /* Use long quantums */
268 QuantumTable += 3;
269 }
270
271 /* Check if we're using long fixed quantums */
272 if (QuantumTable == &PspFixedQuantums[3])
273 {
274 /* Use Job scheduling classes */
275 PspUseJobSchedulingClasses = TRUE;
276 }
277 else
278 {
279 /* Otherwise, we don't */
280 PspUseJobSchedulingClasses = FALSE;
281 }
282
283 /* Copy the selected table into the Foreground Quantum table */
284 RtlCopyMemory(PspForegroundQuantum,
285 QuantumTable,
286 sizeof(PspForegroundQuantum));
287
288 /* Check if we should apply these changes real-time */
289 if (Immediate)
290 {
291 /* We are...loop every process */
292 Process = PsGetNextProcess(Process);
293 while (Process)
294 {
295 /*
296 * Use the priority separation, unless the process has
297 * low memory priority
298 */
299 i = (Process->Vm.Flags.MemoryPriority == 1) ?
300 0: PsPrioritySeparation;
301
302 /* Make sure that the process isn't idle */
303 if (Process->PriorityClass != PROCESS_PRIORITY_CLASS_IDLE)
304 {
305 /* Does the process have a job? */
306 if ((Process->Job) && (PspUseJobSchedulingClasses))
307 {
308 /* Use job quantum */
309 Quantum = PspJobSchedulingClasses[Process->Job->
310 SchedulingClass];
311 }
312 else
313 {
314 /* Use calculated quantum */
315 Quantum = PspForegroundQuantum[i];
316 }
317 }
318 else
319 {
320 /* Process is idle, use default quantum */
321 Quantum = 6;
322 }
323
324 /* Now set the quantum */
325 KeSetQuantumProcess(&Process->Pcb, Quantum);
326
327 /* Get the next process */
328 Process = PsGetNextProcess(Process);
329 }
330 }
331 }
332
333 NTSTATUS
334 NTAPI
335 PspCreateProcess(OUT PHANDLE ProcessHandle,
336 IN ACCESS_MASK DesiredAccess,
337 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
338 IN HANDLE ParentProcess OPTIONAL,
339 IN ULONG Flags,
340 IN HANDLE SectionHandle OPTIONAL,
341 IN HANDLE DebugPort OPTIONAL,
342 IN HANDLE ExceptionPort OPTIONAL,
343 IN BOOLEAN InJob)
344 {
345 HANDLE hProcess;
346 PEPROCESS Process, Parent;
347 PVOID ExceptionPortObject;
348 PDEBUG_OBJECT DebugObject;
349 PSECTION_OBJECT SectionObject;
350 NTSTATUS Status, AccessStatus;
351 ULONG_PTR DirectoryTableBase[2] = {0,0};
352 KAFFINITY Affinity;
353 HANDLE_TABLE_ENTRY CidEntry;
354 PETHREAD CurrentThread = PsGetCurrentThread();
355 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
356 PEPROCESS CurrentProcess = PsGetCurrentProcess();
357 ULONG MinWs, MaxWs;
358 ACCESS_STATE LocalAccessState;
359 PACCESS_STATE AccessState = &LocalAccessState;
360 AUX_ACCESS_DATA AuxData;
361 UCHAR Quantum;
362 BOOLEAN Result, SdAllocated;
363 PSECURITY_DESCRIPTOR SecurityDescriptor;
364 SECURITY_SUBJECT_CONTEXT SubjectContext;
365 BOOLEAN NeedsPeb = FALSE;
366 INITIAL_PEB InitialPeb;
367 PAGED_CODE();
368 PSTRACE(PS_PROCESS_DEBUG,
369 "ProcessHandle: %p Parent: %p\n", ProcessHandle, ParentProcess);
370
371 /* Validate flags */
372 if (Flags & ~PROCESS_CREATE_FLAGS_LEGAL_MASK) return STATUS_INVALID_PARAMETER;
373
374 /* Check for parent */
375 if (ParentProcess)
376 {
377 /* Reference it */
378 Status = ObReferenceObjectByHandle(ParentProcess,
379 PROCESS_CREATE_PROCESS,
380 PsProcessType,
381 PreviousMode,
382 (PVOID*)&Parent,
383 NULL);
384 if (!NT_SUCCESS(Status)) return Status;
385
386 /* If this process should be in a job but the parent isn't */
387 if ((InJob) && (!Parent->Job))
388 {
389 /* This is illegal. Dereference the parent and fail */
390 ObDereferenceObject(Parent);
391 return STATUS_INVALID_PARAMETER;
392 }
393
394 /* Inherit Parent process's Affinity. */
395 Affinity = Parent->Pcb.Affinity;
396 }
397 else
398 {
399 /* We have no parent */
400 Parent = NULL;
401 Affinity = KeActiveProcessors;
402 }
403
404 /* Save working set data */
405 MinWs = PsMinimumWorkingSet;
406 MaxWs = PsMaximumWorkingSet;
407
408 /* Create the Object */
409 Status = ObCreateObject(PreviousMode,
410 PsProcessType,
411 ObjectAttributes,
412 PreviousMode,
413 NULL,
414 sizeof(EPROCESS),
415 0,
416 0,
417 (PVOID*)&Process);
418 if (!NT_SUCCESS(Status)) goto Cleanup;
419
420 /* Clean up the Object */
421 RtlZeroMemory(Process, sizeof(EPROCESS));
422
423 /* Initialize pushlock and rundown protection */
424 ExInitializeRundownProtection(&Process->RundownProtect);
425 Process->ProcessLock.Value = 0;
426
427 /* Setup the Thread List Head */
428 InitializeListHead(&Process->ThreadListHead);
429
430 /* Set up the Quota Block from the Parent */
431 PspInheritQuota(Process, Parent);
432
433 /* Set up Dos Device Map from the Parent */
434 ObInheritDeviceMap(Parent, Process);
435
436 /* Check if we have a parent */
437 if (Parent)
438 {
439 /* Inherit PID and Hard Error Processing */
440 Process->InheritedFromUniqueProcessId = Parent->UniqueProcessId;
441 Process->DefaultHardErrorProcessing = Parent->
442 DefaultHardErrorProcessing;
443 }
444 else
445 {
446 /* Use default hard error processing */
447 Process->DefaultHardErrorProcessing = TRUE;
448 }
449
450 /* Check for a section handle */
451 if (SectionHandle)
452 {
453 /* Get a pointer to it */
454 Status = ObReferenceObjectByHandle(SectionHandle,
455 SECTION_MAP_EXECUTE,
456 MmSectionObjectType,
457 PreviousMode,
458 (PVOID*)&SectionObject,
459 NULL);
460 if (!NT_SUCCESS(Status)) goto CleanupWithRef;
461 }
462 else
463 {
464 /* Assume no section object */
465 SectionObject = NULL;
466
467 /* Is the parent the initial process?
468 * Check for NULL also, as at initialization PsInitialSystemProcess is NULL */
469 if (Parent != PsInitialSystemProcess && (Parent != NULL))
470 {
471 /* It's not, so acquire the process rundown */
472 if (ExAcquireRundownProtection(&Parent->RundownProtect))
473 {
474 /* If the parent has a section, use it */
475 SectionObject = Parent->SectionObject;
476 if (SectionObject) ObReferenceObject(SectionObject);
477
478 /* Release process rundown */
479 ExReleaseRundownProtection(&Parent->RundownProtect);
480 }
481
482 /* If we don't have a section object */
483 if (!SectionObject)
484 {
485 /* Then the process is in termination, so fail */
486 Status = STATUS_PROCESS_IS_TERMINATING;
487 goto CleanupWithRef;
488 }
489 }
490 }
491
492 /* Save the pointer to the section object */
493 Process->SectionObject = SectionObject;
494
495 /* Check for the debug port */
496 if (DebugPort)
497 {
498 /* Reference it */
499 Status = ObReferenceObjectByHandle(DebugPort,
500 DEBUG_OBJECT_ADD_REMOVE_PROCESS,
501 DbgkDebugObjectType,
502 PreviousMode,
503 (PVOID*)&DebugObject,
504 NULL);
505 if (!NT_SUCCESS(Status)) goto CleanupWithRef;
506
507 /* Save the debug object */
508 Process->DebugPort = DebugObject;
509
510 /* Check if the caller doesn't want the debug stuff inherited */
511 if (Flags & PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT)
512 {
513 /* Set the process flag */
514 InterlockedOr((PLONG)&Process->Flags, PSF_NO_DEBUG_INHERIT_BIT);
515 }
516 }
517 else
518 {
519 /* Do we have a parent? Copy his debug port */
520 if (Parent) DbgkCopyProcessDebugPort(Process, Parent);
521 }
522
523 /* Now check for an exception port */
524 if (ExceptionPort)
525 {
526 /* Reference it */
527 Status = ObReferenceObjectByHandle(ExceptionPort,
528 PORT_ALL_ACCESS,
529 LpcPortObjectType,
530 PreviousMode,
531 (PVOID*)&ExceptionPortObject,
532 NULL);
533 if (!NT_SUCCESS(Status)) goto CleanupWithRef;
534
535 /* Save the exception port */
536 Process->ExceptionPort = ExceptionPortObject;
537 }
538
539 /* Save the pointer to the section object */
540 Process->SectionObject = SectionObject;
541
542 /* Set default exit code */
543 Process->ExitStatus = STATUS_PENDING;
544
545 /* Check if this is the initial process being built */
546 if (Parent)
547 {
548 /* Create the address space for the child */
549 if (!MmCreateProcessAddressSpace(MinWs,
550 Process,
551 DirectoryTableBase))
552 {
553 /* Failed */
554 Status = STATUS_INSUFFICIENT_RESOURCES;
555 goto CleanupWithRef;
556 }
557 }
558 else
559 {
560 /* Otherwise, we are the boot process, we're already semi-initialized */
561 Process->ObjectTable = CurrentProcess->ObjectTable;
562 Status = MmInitializeHandBuiltProcess(Process, DirectoryTableBase);
563 if (!NT_SUCCESS(Status)) goto CleanupWithRef;
564 }
565
566 /* We now have an address space */
567 InterlockedOr((PLONG)&Process->Flags, PSF_HAS_ADDRESS_SPACE_BIT);
568
569 /* Set the maximum WS */
570 Process->Vm.MaximumWorkingSetSize = MaxWs;
571
572 /* Now initialize the Kernel Process */
573 KeInitializeProcess(&Process->Pcb,
574 PROCESS_PRIORITY_NORMAL,
575 Affinity,
576 DirectoryTableBase,
577 (BOOLEAN)(Process->DefaultHardErrorProcessing & 4));
578
579 /* Duplicate Parent Token */
580 Status = PspInitializeProcessSecurity(Process, Parent);
581 if (!NT_SUCCESS(Status)) goto CleanupWithRef;
582
583 /* Set default priority class */
584 Process->PriorityClass = PROCESS_PRIORITY_CLASS_NORMAL;
585
586 /* Check if we have a parent */
587 if (Parent)
588 {
589 /* Check our priority class */
590 if (Parent->PriorityClass == PROCESS_PRIORITY_CLASS_IDLE ||
591 Parent->PriorityClass == PROCESS_PRIORITY_CLASS_BELOW_NORMAL)
592 {
593 /* Normalize it */
594 Process->PriorityClass = Parent->PriorityClass;
595 }
596
597 /* Initialize object manager for the process */
598 Status = ObInitProcess(Flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES ?
599 Parent : NULL,
600 Process);
601 if (!NT_SUCCESS(Status)) goto CleanupWithRef;
602 }
603 else
604 {
605 /* Do the second part of the boot process memory setup */
606 Status = MmInitializeHandBuiltProcess2(Process);
607 if (!NT_SUCCESS(Status)) goto CleanupWithRef;
608 }
609
610 /* Set success for now */
611 Status = STATUS_SUCCESS;
612
613 /* Check if this is a real user-mode process */
614 if (SectionHandle)
615 {
616 /* Initialize the address space */
617 Status = MmInitializeProcessAddressSpace(Process,
618 NULL,
619 SectionObject,
620 &Flags,
621 &Process->
622 SeAuditProcessCreationInfo.
623 ImageFileName);
624 if (!NT_SUCCESS(Status)) goto CleanupWithRef;
625
626 //
627 // We need a PEB
628 //
629 NeedsPeb = TRUE;
630 }
631 else if (Parent)
632 {
633 /* Check if this is a child of the system process */
634 if (Parent != PsInitialSystemProcess)
635 {
636 //
637 // We need a PEB
638 //
639 NeedsPeb = TRUE;
640
641 /* This is a clone! */
642 ASSERTMSG("No support for cloning yet\n", FALSE);
643 }
644 else
645 {
646 /* This is the initial system process */
647 Flags &= ~PROCESS_CREATE_FLAGS_LARGE_PAGES;
648 Status = MmInitializeProcessAddressSpace(Process,
649 NULL,
650 NULL,
651 &Flags,
652 NULL);
653 if (!NT_SUCCESS(Status)) goto CleanupWithRef;
654
655 /* Create a dummy image file name */
656 Process->SeAuditProcessCreationInfo.ImageFileName =
657 ExAllocatePoolWithTag(PagedPool,
658 sizeof(OBJECT_NAME_INFORMATION),
659 TAG_SEPA);
660 if (!Process->SeAuditProcessCreationInfo.ImageFileName)
661 {
662 /* Fail */
663 Status = STATUS_INSUFFICIENT_RESOURCES;
664 goto CleanupWithRef;
665 }
666
667 /* Zero it out */
668 RtlZeroMemory(Process->SeAuditProcessCreationInfo.ImageFileName,
669 sizeof(OBJECT_NAME_INFORMATION));
670 }
671 }
672
673 #if MI_TRACE_PFNS
674 /* Copy the process name now that we have it */
675 memcpy(MiGetPfnEntry(Process->Pcb.DirectoryTableBase[0] >> PAGE_SHIFT)->ProcessName, Process->ImageFileName, 16);
676 if (Process->Pcb.DirectoryTableBase[1]) memcpy(MiGetPfnEntry(Process->Pcb.DirectoryTableBase[1] >> PAGE_SHIFT)->ProcessName, Process->ImageFileName, 16);
677 if (Process->WorkingSetPage) memcpy(MiGetPfnEntry(Process->WorkingSetPage)->ProcessName, Process->ImageFileName, 16);
678 #endif
679
680 /* Check if we have a section object and map the system DLL */
681 if (SectionObject) PspMapSystemDll(Process, NULL, FALSE);
682
683 /* Create a handle for the Process */
684 CidEntry.Object = Process;
685 CidEntry.GrantedAccess = 0;
686 Process->UniqueProcessId = ExCreateHandle(PspCidTable, &CidEntry);
687 if (!Process->UniqueProcessId)
688 {
689 /* Fail */
690 Status = STATUS_INSUFFICIENT_RESOURCES;
691 goto CleanupWithRef;
692 }
693
694 /* Set the handle table PID */
695 Process->ObjectTable->UniqueProcessId = Process->UniqueProcessId;
696
697 /* Check if we need to audit */
698 if (SeDetailedAuditingWithToken(NULL)) SeAuditProcessCreate(Process);
699
700 /* Check if the parent had a job */
701 if ((Parent) && (Parent->Job))
702 {
703 /* FIXME: We need to insert this process */
704 DPRINT1("Jobs not yet supported\n");
705 ASSERT(FALSE);
706 }
707
708 /* Create PEB only for User-Mode Processes */
709 if ((Parent) && (NeedsPeb))
710 {
711 //
712 // Set up the initial PEB
713 //
714 RtlZeroMemory(&InitialPeb, sizeof(INITIAL_PEB));
715 InitialPeb.Mutant = (HANDLE)-1;
716 InitialPeb.ImageUsesLargePages = 0; // FIXME: Not yet supported
717
718 //
719 // Create it only if we have an image section
720 //
721 if (SectionHandle)
722 {
723 //
724 // Create it
725 //
726 Status = MmCreatePeb(Process, &InitialPeb, &Process->Peb);
727 if (!NT_SUCCESS(Status)) goto CleanupWithRef;
728 }
729 else
730 {
731 //
732 // We have to clone it
733 //
734 ASSERTMSG("No support for cloning yet\n", FALSE);
735 }
736
737 }
738
739 /* The process can now be activated */
740 KeAcquireGuardedMutex(&PspActiveProcessMutex);
741 InsertTailList(&PsActiveProcessHead, &Process->ActiveProcessLinks);
742 KeReleaseGuardedMutex(&PspActiveProcessMutex);
743
744 /* Create an access state */
745 Status = SeCreateAccessStateEx(CurrentThread,
746 ((Parent) &&
747 (Parent == PsInitialSystemProcess)) ?
748 Parent : CurrentProcess,
749 &LocalAccessState,
750 &AuxData,
751 DesiredAccess,
752 &PsProcessType->TypeInfo.GenericMapping);
753 if (!NT_SUCCESS(Status)) goto CleanupWithRef;
754
755 /* Insert the Process into the Object Directory */
756 Status = ObInsertObject(Process,
757 AccessState,
758 DesiredAccess,
759 1,
760 NULL,
761 &hProcess);
762
763 /* Free the access state */
764 if (AccessState) SeDeleteAccessState(AccessState);
765
766 /* Cleanup on failure */
767 if (!NT_SUCCESS(Status)) goto Cleanup;
768
769 /* Compute Quantum and Priority */
770 ASSERT(IsListEmpty(&Process->ThreadListHead) == TRUE);
771 Process->Pcb.BasePriority =
772 (SCHAR)PspComputeQuantumAndPriority(Process,
773 PsProcessPriorityBackground,
774 &Quantum);
775 Process->Pcb.QuantumReset = Quantum;
776
777 /* Check if we have a parent other then the initial system process */
778 Process->GrantedAccess = PROCESS_TERMINATE;
779 if ((Parent) && (Parent != PsInitialSystemProcess))
780 {
781 /* Get the process's SD */
782 Status = ObGetObjectSecurity(Process,
783 &SecurityDescriptor,
784 &SdAllocated);
785 if (!NT_SUCCESS(Status))
786 {
787 /* We failed, close the handle and clean up */
788 ObCloseHandle(hProcess, PreviousMode);
789 goto CleanupWithRef;
790 }
791
792 /* Create the subject context */
793 SubjectContext.ProcessAuditId = Process;
794 SubjectContext.PrimaryToken = PsReferencePrimaryToken(Process);
795 SubjectContext.ClientToken = NULL;
796
797 /* Do the access check */
798 Result = SeAccessCheck(SecurityDescriptor,
799 &SubjectContext,
800 FALSE,
801 MAXIMUM_ALLOWED,
802 0,
803 NULL,
804 &PsProcessType->TypeInfo.GenericMapping,
805 PreviousMode,
806 &Process->GrantedAccess,
807 &AccessStatus);
808
809 /* Dereference the token and let go the SD */
810 ObFastDereferenceObject(&Process->Token,
811 SubjectContext.PrimaryToken);
812 ObReleaseObjectSecurity(SecurityDescriptor, SdAllocated);
813
814 /* Remove access if it failed */
815 if (!Result) Process->GrantedAccess = 0;
816
817 /* Give the process some basic access */
818 Process->GrantedAccess |= (PROCESS_VM_OPERATION |
819 PROCESS_VM_READ |
820 PROCESS_VM_WRITE |
821 PROCESS_QUERY_INFORMATION |
822 PROCESS_TERMINATE |
823 PROCESS_CREATE_THREAD |
824 PROCESS_DUP_HANDLE |
825 PROCESS_CREATE_PROCESS |
826 PROCESS_SET_INFORMATION |
827 STANDARD_RIGHTS_ALL |
828 PROCESS_SET_QUOTA);
829 }
830 else
831 {
832 /* Set full granted access */
833 Process->GrantedAccess = PROCESS_ALL_ACCESS;
834 }
835
836 /* Set the Creation Time */
837 KeQuerySystemTime(&Process->CreateTime);
838
839 /* Protect against bad user-mode pointer */
840 _SEH2_TRY
841 {
842 /* Hacky way of returning the PEB to the user-mode creator */
843 if ((Process->Peb) && (CurrentThread->Tcb.Teb))
844 {
845 CurrentThread->Tcb.Teb->NtTib.ArbitraryUserPointer = Process->Peb;
846 }
847
848 /* Save the process handle */
849 *ProcessHandle = hProcess;
850 }
851 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
852 {
853 /* Get the exception code */
854 Status = _SEH2_GetExceptionCode();
855 }
856 _SEH2_END;
857
858 /* Run the Notification Routines */
859 PspRunCreateProcessNotifyRoutines(Process, TRUE);
860
861 /* If 12 processes have been created, enough of user-mode is ready */
862 if (++ProcessCount == 12) Ki386PerfEnd();
863
864 CleanupWithRef:
865 /*
866 * Dereference the process. For failures, kills the process and does
867 * cleanup present in PspDeleteProcess. For success, kills the extra
868 * reference added by ObInsertObject.
869 */
870 ObDereferenceObject(Process);
871
872 Cleanup:
873 /* Dereference the parent */
874 if (Parent) ObDereferenceObject(Parent);
875
876 /* Return status to caller */
877 return Status;
878 }
879
880 /* PUBLIC FUNCTIONS **********************************************************/
881
882 /*
883 * @implemented
884 */
885 NTSTATUS
886 NTAPI
887 PsCreateSystemProcess(OUT PHANDLE ProcessHandle,
888 IN ACCESS_MASK DesiredAccess,
889 IN POBJECT_ATTRIBUTES ObjectAttributes)
890 {
891 /* Call the internal API */
892 return PspCreateProcess(ProcessHandle,
893 DesiredAccess,
894 ObjectAttributes,
895 NULL,
896 0,
897 NULL,
898 NULL,
899 NULL,
900 FALSE);
901 }
902
903 /*
904 * @implemented
905 */
906 NTSTATUS
907 NTAPI
908 PsLookupProcessByProcessId(IN HANDLE ProcessId,
909 OUT PEPROCESS *Process)
910 {
911 PHANDLE_TABLE_ENTRY CidEntry;
912 PEPROCESS FoundProcess;
913 NTSTATUS Status = STATUS_INVALID_PARAMETER;
914 PAGED_CODE();
915 PSTRACE(PS_PROCESS_DEBUG, "ProcessId: %p\n", ProcessId);
916 KeEnterCriticalRegion();
917
918 /* Get the CID Handle Entry */
919 CidEntry = ExMapHandleToPointer(PspCidTable, ProcessId);
920 if (CidEntry)
921 {
922 /* Get the Process */
923 FoundProcess = CidEntry->Object;
924
925 /* Make sure it's really a process */
926 if (FoundProcess->Pcb.Header.Type == ProcessObject)
927 {
928 /* Safe Reference and return it */
929 if (ObReferenceObjectSafe(FoundProcess))
930 {
931 *Process = FoundProcess;
932 Status = STATUS_SUCCESS;
933 }
934 }
935
936 /* Unlock the Entry */
937 ExUnlockHandleTableEntry(PspCidTable, CidEntry);
938 }
939
940 /* Return to caller */
941 KeLeaveCriticalRegion();
942 return Status;
943 }
944
945 /*
946 * @implemented
947 */
948 NTSTATUS
949 NTAPI
950 PsLookupProcessThreadByCid(IN PCLIENT_ID Cid,
951 OUT PEPROCESS *Process OPTIONAL,
952 OUT PETHREAD *Thread)
953 {
954 PHANDLE_TABLE_ENTRY CidEntry;
955 PETHREAD FoundThread;
956 NTSTATUS Status = STATUS_INVALID_CID;
957 PAGED_CODE();
958 PSTRACE(PS_PROCESS_DEBUG, "Cid: %p\n", Cid);
959 KeEnterCriticalRegion();
960
961 /* Get the CID Handle Entry */
962 CidEntry = ExMapHandleToPointer(PspCidTable, Cid->UniqueThread);
963 if (CidEntry)
964 {
965 /* Get the Process */
966 FoundThread = CidEntry->Object;
967
968 /* Make sure it's really a thread and this process' */
969 if ((FoundThread->Tcb.Header.Type == ThreadObject) &&
970 (FoundThread->Cid.UniqueProcess == Cid->UniqueProcess))
971 {
972 /* Safe Reference and return it */
973 if (ObReferenceObjectSafe(FoundThread))
974 {
975 *Thread = FoundThread;
976 Status = STATUS_SUCCESS;
977
978 /* Check if we should return the Process too */
979 if (Process)
980 {
981 /* Return it and reference it */
982 *Process = FoundThread->ThreadsProcess;
983 ObReferenceObject(*Process);
984 }
985 }
986 }
987
988 /* Unlock the Entry */
989 ExUnlockHandleTableEntry(PspCidTable, CidEntry);
990 }
991
992 /* Return to caller */
993 KeLeaveCriticalRegion();
994 return Status;
995 }
996
997 /*
998 * @implemented
999 */
1000 LARGE_INTEGER
1001 NTAPI
1002 PsGetProcessExitTime(VOID)
1003 {
1004 return PsGetCurrentProcess()->ExitTime;
1005 }
1006
1007 /*
1008 * @implemented
1009 */
1010 LONGLONG
1011 NTAPI
1012 PsGetProcessCreateTimeQuadPart(PEPROCESS Process)
1013 {
1014 return Process->CreateTime.QuadPart;
1015 }
1016
1017 /*
1018 * @implemented
1019 */
1020 PVOID
1021 NTAPI
1022 PsGetProcessDebugPort(PEPROCESS Process)
1023 {
1024 return Process->DebugPort;
1025 }
1026
1027 /*
1028 * @implemented
1029 */
1030 BOOLEAN
1031 NTAPI
1032 PsGetProcessExitProcessCalled(PEPROCESS Process)
1033 {
1034 return (BOOLEAN)Process->ProcessExiting;
1035 }
1036
1037 /*
1038 * @implemented
1039 */
1040 NTSTATUS
1041 NTAPI
1042 PsGetProcessExitStatus(PEPROCESS Process)
1043 {
1044 return Process->ExitStatus;
1045 }
1046
1047 /*
1048 * @implemented
1049 */
1050 HANDLE
1051 NTAPI
1052 PsGetProcessId(PEPROCESS Process)
1053 {
1054 return (HANDLE)Process->UniqueProcessId;
1055 }
1056
1057 /*
1058 * @implemented
1059 */
1060 LPSTR
1061 NTAPI
1062 PsGetProcessImageFileName(PEPROCESS Process)
1063 {
1064 return (LPSTR)Process->ImageFileName;
1065 }
1066
1067 /*
1068 * @implemented
1069 */
1070 HANDLE
1071 NTAPI
1072 PsGetProcessInheritedFromUniqueProcessId(PEPROCESS Process)
1073 {
1074 return Process->InheritedFromUniqueProcessId;
1075 }
1076
1077 /*
1078 * @implemented
1079 */
1080 PEJOB
1081 NTAPI
1082 PsGetProcessJob(PEPROCESS Process)
1083 {
1084 return Process->Job;
1085 }
1086
1087 /*
1088 * @implemented
1089 */
1090 PPEB
1091 NTAPI
1092 PsGetProcessPeb(PEPROCESS Process)
1093 {
1094 return Process->Peb;
1095 }
1096
1097 /*
1098 * @implemented
1099 */
1100 ULONG
1101 NTAPI
1102 PsGetProcessPriorityClass(PEPROCESS Process)
1103 {
1104 return Process->PriorityClass;
1105 }
1106
1107 /*
1108 * @implemented
1109 */
1110 HANDLE
1111 NTAPI
1112 PsGetCurrentProcessId(VOID)
1113 {
1114 return (HANDLE)PsGetCurrentProcess()->UniqueProcessId;
1115 }
1116
1117 /*
1118 * @implemented
1119 */
1120 ULONG
1121 NTAPI
1122 PsGetCurrentProcessSessionId(VOID)
1123 {
1124 return MmGetSessionId(PsGetCurrentProcess());
1125 }
1126
1127 /*
1128 * @implemented
1129 */
1130 PVOID
1131 NTAPI
1132 PsGetProcessSectionBaseAddress(PEPROCESS Process)
1133 {
1134 return Process->SectionBaseAddress;
1135 }
1136
1137 /*
1138 * @implemented
1139 */
1140 PVOID
1141 NTAPI
1142 PsGetProcessSecurityPort(PEPROCESS Process)
1143 {
1144 return Process->SecurityPort;
1145 }
1146
1147 /*
1148 * @implemented
1149 */
1150 ULONG
1151 NTAPI
1152 PsGetProcessSessionId(IN PEPROCESS Process)
1153 {
1154 return MmGetSessionId(Process);
1155 }
1156
1157 /*
1158 * @implemented
1159 */
1160 ULONG
1161 NTAPI
1162 PsGetProcessSessionIdEx(IN PEPROCESS Process)
1163 {
1164 return MmGetSessionIdEx(Process);
1165 }
1166
1167 /*
1168 * @implemented
1169 */
1170 PVOID
1171 NTAPI
1172 PsGetCurrentProcessWin32Process(VOID)
1173 {
1174 return PsGetCurrentProcess()->Win32Process;
1175 }
1176
1177 /*
1178 * @implemented
1179 */
1180 PVOID
1181 NTAPI
1182 PsGetProcessWin32Process(PEPROCESS Process)
1183 {
1184 return Process->Win32Process;
1185 }
1186
1187 /*
1188 * @implemented
1189 */
1190 PVOID
1191 NTAPI
1192 PsGetProcessWin32WindowStation(PEPROCESS Process)
1193 {
1194 return Process->Win32WindowStation;
1195 }
1196
1197 /*
1198 * @implemented
1199 */
1200 BOOLEAN
1201 NTAPI
1202 PsIsProcessBeingDebugged(PEPROCESS Process)
1203 {
1204 return Process->DebugPort != NULL;
1205 }
1206
1207 /*
1208 * @implemented
1209 */
1210 BOOLEAN
1211 NTAPI
1212 PsIsSystemProcess(IN PEPROCESS Process)
1213 {
1214 /* Return if this is the System Process */
1215 return Process == PsInitialSystemProcess;
1216 }
1217
1218 /*
1219 * @implemented
1220 */
1221 VOID
1222 NTAPI
1223 PsSetProcessPriorityClass(PEPROCESS Process,
1224 ULONG PriorityClass)
1225 {
1226 Process->PriorityClass = (UCHAR)PriorityClass;
1227 }
1228
1229 /*
1230 * @implemented
1231 */
1232 NTSTATUS
1233 NTAPI
1234 PsSetProcessSecurityPort(PEPROCESS Process,
1235 PVOID SecurityPort)
1236 {
1237 Process->SecurityPort = SecurityPort;
1238 return STATUS_SUCCESS;
1239 }
1240
1241 /*
1242 * @implemented
1243 */
1244 NTSTATUS
1245 NTAPI
1246 PsSetProcessWin32Process(
1247 _Inout_ PEPROCESS Process,
1248 _In_opt_ PVOID Win32Process,
1249 _In_opt_ PVOID OldWin32Process)
1250 {
1251 NTSTATUS Status;
1252
1253 /* Assume success */
1254 Status = STATUS_SUCCESS;
1255
1256 /* Lock the process */
1257 KeEnterCriticalRegion();
1258 ExAcquirePushLockExclusive(&Process->ProcessLock);
1259
1260 /* Check if we set a new win32 process */
1261 if (Win32Process != NULL)
1262 {
1263 /* Check if the process is in the right state */
1264 if (((Process->Flags & PSF_PROCESS_DELETE_BIT) == 0) &&
1265 (Process->Win32Process == NULL))
1266 {
1267 /* Set the new win32 process */
1268 Process->Win32Process = Win32Process;
1269 }
1270 else
1271 {
1272 /* Otherwise fail */
1273 Status = STATUS_PROCESS_IS_TERMINATING;
1274 }
1275 }
1276 else
1277 {
1278 /* Reset the win32 process, did the caller specify the correct old value? */
1279 if (Process->Win32Process == OldWin32Process)
1280 {
1281 /* Yes, so reset the win32 process to NULL */
1282 Process->Win32Process = 0;
1283 }
1284 else
1285 {
1286 /* Otherwise fail */
1287 Status = STATUS_UNSUCCESSFUL;
1288 }
1289 }
1290
1291 /* Unlock the process */
1292 ExReleasePushLockExclusive(&Process->ProcessLock);
1293 KeLeaveCriticalRegion();
1294
1295 return Status;
1296 }
1297
1298 /*
1299 * @implemented
1300 */
1301 VOID
1302 NTAPI
1303 PsSetProcessWindowStation(PEPROCESS Process,
1304 PVOID WindowStation)
1305 {
1306 Process->Win32WindowStation = WindowStation;
1307 }
1308
1309 /*
1310 * @implemented
1311 */
1312 VOID
1313 NTAPI
1314 PsSetProcessPriorityByClass(IN PEPROCESS Process,
1315 IN PSPROCESSPRIORITYMODE Type)
1316 {
1317 UCHAR Quantum;
1318 ULONG Priority;
1319 PSTRACE(PS_PROCESS_DEBUG, "Process: %p Type: %lx\n", Process, Type);
1320
1321 /* Compute quantum and priority */
1322 Priority = PspComputeQuantumAndPriority(Process, Type, &Quantum);
1323
1324 /* Set them */
1325 KeSetPriorityAndQuantumProcess(&Process->Pcb, Priority, Quantum);
1326 }
1327
1328 /*
1329 * @implemented
1330 */
1331 NTSTATUS
1332 NTAPI
1333 NtCreateProcessEx(OUT PHANDLE ProcessHandle,
1334 IN ACCESS_MASK DesiredAccess,
1335 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
1336 IN HANDLE ParentProcess,
1337 IN ULONG Flags,
1338 IN HANDLE SectionHandle OPTIONAL,
1339 IN HANDLE DebugPort OPTIONAL,
1340 IN HANDLE ExceptionPort OPTIONAL,
1341 IN BOOLEAN InJob)
1342 {
1343 KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
1344 NTSTATUS Status;
1345 PAGED_CODE();
1346 PSTRACE(PS_PROCESS_DEBUG,
1347 "ParentProcess: %p Flags: %lx\n", ParentProcess, Flags);
1348
1349 /* Check if we came from user mode */
1350 if (PreviousMode != KernelMode)
1351 {
1352 _SEH2_TRY
1353 {
1354 /* Probe process handle */
1355 ProbeForWriteHandle(ProcessHandle);
1356 }
1357 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1358 {
1359 /* Return the exception code */
1360 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1361 }
1362 _SEH2_END;
1363 }
1364
1365 /* Make sure there's a parent process */
1366 if (!ParentProcess)
1367 {
1368 /* Can't create System Processes like this */
1369 Status = STATUS_INVALID_PARAMETER;
1370 }
1371 else
1372 {
1373 /* Create a user Process */
1374 Status = PspCreateProcess(ProcessHandle,
1375 DesiredAccess,
1376 ObjectAttributes,
1377 ParentProcess,
1378 Flags,
1379 SectionHandle,
1380 DebugPort,
1381 ExceptionPort,
1382 InJob);
1383 }
1384
1385 /* Return Status */
1386 return Status;
1387 }
1388
1389 /*
1390 * @implemented
1391 */
1392 NTSTATUS
1393 NTAPI
1394 NtCreateProcess(OUT PHANDLE ProcessHandle,
1395 IN ACCESS_MASK DesiredAccess,
1396 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
1397 IN HANDLE ParentProcess,
1398 IN BOOLEAN InheritObjectTable,
1399 IN HANDLE SectionHandle OPTIONAL,
1400 IN HANDLE DebugPort OPTIONAL,
1401 IN HANDLE ExceptionPort OPTIONAL)
1402 {
1403 ULONG Flags = 0;
1404 PSTRACE(PS_PROCESS_DEBUG,
1405 "Parent: %p Attributes: %p\n", ParentProcess, ObjectAttributes);
1406
1407 /* Set new-style flags */
1408 if ((ULONG)SectionHandle & 1) Flags |= PROCESS_CREATE_FLAGS_BREAKAWAY;
1409 if ((ULONG)DebugPort & 1) Flags |= PROCESS_CREATE_FLAGS_NO_DEBUG_INHERIT;
1410 if (InheritObjectTable) Flags |= PROCESS_CREATE_FLAGS_INHERIT_HANDLES;
1411
1412 /* Call the new API */
1413 return NtCreateProcessEx(ProcessHandle,
1414 DesiredAccess,
1415 ObjectAttributes,
1416 ParentProcess,
1417 Flags,
1418 SectionHandle,
1419 DebugPort,
1420 ExceptionPort,
1421 FALSE);
1422 }
1423
1424 /*
1425 * @implemented
1426 */
1427 NTSTATUS
1428 NTAPI
1429 NtOpenProcess(OUT PHANDLE ProcessHandle,
1430 IN ACCESS_MASK DesiredAccess,
1431 IN POBJECT_ATTRIBUTES ObjectAttributes,
1432 IN PCLIENT_ID ClientId)
1433 {
1434 KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
1435 CLIENT_ID SafeClientId;
1436 ULONG Attributes = 0;
1437 HANDLE hProcess;
1438 BOOLEAN HasObjectName = FALSE;
1439 PETHREAD Thread = NULL;
1440 PEPROCESS Process = NULL;
1441 NTSTATUS Status;
1442 ACCESS_STATE AccessState;
1443 AUX_ACCESS_DATA AuxData;
1444 PAGED_CODE();
1445 PSTRACE(PS_PROCESS_DEBUG,
1446 "ClientId: %p Attributes: %p\n", ClientId, ObjectAttributes);
1447
1448 /* Check if we were called from user mode */
1449 if (PreviousMode != KernelMode)
1450 {
1451 /* Enter SEH for probing */
1452 _SEH2_TRY
1453 {
1454 /* Probe the thread handle */
1455 ProbeForWriteHandle(ProcessHandle);
1456
1457 /* Check for a CID structure */
1458 if (ClientId)
1459 {
1460 /* Probe and capture it */
1461 ProbeForRead(ClientId, sizeof(CLIENT_ID), sizeof(ULONG));
1462 SafeClientId = *ClientId;
1463 ClientId = &SafeClientId;
1464 }
1465
1466 /*
1467 * Just probe the object attributes structure, don't capture it
1468 * completely. This is done later if necessary
1469 */
1470 ProbeForRead(ObjectAttributes,
1471 sizeof(OBJECT_ATTRIBUTES),
1472 sizeof(ULONG));
1473 HasObjectName = (ObjectAttributes->ObjectName != NULL);
1474 Attributes = ObjectAttributes->Attributes;
1475 }
1476 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1477 {
1478 /* Return the exception code */
1479 _SEH2_YIELD(return _SEH2_GetExceptionCode());
1480 }
1481 _SEH2_END;
1482 }
1483 else
1484 {
1485 /* Otherwise just get the data directly */
1486 HasObjectName = (ObjectAttributes->ObjectName != NULL);
1487 Attributes = ObjectAttributes->Attributes;
1488 }
1489
1490 /* Can't pass both, fail */
1491 if ((HasObjectName) && (ClientId)) return STATUS_INVALID_PARAMETER_MIX;
1492
1493 /* Create an access state */
1494 Status = SeCreateAccessState(&AccessState,
1495 &AuxData,
1496 DesiredAccess,
1497 &PsProcessType->TypeInfo.GenericMapping);
1498 if (!NT_SUCCESS(Status)) return Status;
1499
1500 /* Check if this is a debugger */
1501 if (SeSinglePrivilegeCheck(SeDebugPrivilege, PreviousMode))
1502 {
1503 /* Did he want full access? */
1504 if (AccessState.RemainingDesiredAccess & MAXIMUM_ALLOWED)
1505 {
1506 /* Give it to him */
1507 AccessState.PreviouslyGrantedAccess |= PROCESS_ALL_ACCESS;
1508 }
1509 else
1510 {
1511 /* Otherwise just give every other access he could want */
1512 AccessState.PreviouslyGrantedAccess |=
1513 AccessState.RemainingDesiredAccess;
1514 }
1515
1516 /* The caller desires nothing else now */
1517 AccessState.RemainingDesiredAccess = 0;
1518 }
1519
1520 /* Open by name if one was given */
1521 if (HasObjectName)
1522 {
1523 /* Open it */
1524 Status = ObOpenObjectByName(ObjectAttributes,
1525 PsProcessType,
1526 PreviousMode,
1527 &AccessState,
1528 0,
1529 NULL,
1530 &hProcess);
1531
1532 /* Get rid of the access state */
1533 SeDeleteAccessState(&AccessState);
1534 }
1535 else if (ClientId)
1536 {
1537 /* Open by Thread ID */
1538 if (ClientId->UniqueThread)
1539 {
1540 /* Get the Process */
1541 Status = PsLookupProcessThreadByCid(ClientId, &Process, &Thread);
1542 }
1543 else
1544 {
1545 /* Get the Process */
1546 Status = PsLookupProcessByProcessId(ClientId->UniqueProcess,
1547 &Process);
1548 }
1549
1550 /* Check if we didn't find anything */
1551 if (!NT_SUCCESS(Status))
1552 {
1553 /* Get rid of the access state and return */
1554 SeDeleteAccessState(&AccessState);
1555 return Status;
1556 }
1557
1558 /* Open the Process Object */
1559 Status = ObOpenObjectByPointer(Process,
1560 Attributes,
1561 &AccessState,
1562 0,
1563 PsProcessType,
1564 PreviousMode,
1565 &hProcess);
1566
1567 /* Delete the access state */
1568 SeDeleteAccessState(&AccessState);
1569
1570 /* Dereference the thread if we used it */
1571 if (Thread) ObDereferenceObject(Thread);
1572
1573 /* Dereference the Process */
1574 ObDereferenceObject(Process);
1575 }
1576 else
1577 {
1578 /* neither an object name nor a client id was passed */
1579 return STATUS_INVALID_PARAMETER_MIX;
1580 }
1581
1582 /* Check for success */
1583 if (NT_SUCCESS(Status))
1584 {
1585 /* Use SEH for write back */
1586 _SEH2_TRY
1587 {
1588 /* Write back the handle */
1589 *ProcessHandle = hProcess;
1590 }
1591 _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
1592 {
1593 /* Get the exception code */
1594 Status = _SEH2_GetExceptionCode();
1595 }
1596 _SEH2_END;
1597 }
1598
1599 /* Return status */
1600 return Status;
1601 }
1602 /* EOF */