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