update for HEAD-2003091401
[reactos.git] / ntoskrnl / ps / process.c
1 /* $Id$
2  *
3  * COPYRIGHT:         See COPYING in the top level directory
4  * PROJECT:           ReactOS kernel
5  * FILE:              ntoskrnl/ps/process.c
6  * PURPOSE:           Process managment
7  * PROGRAMMER:        David Welch (welch@cwcom.net)
8  * REVISION HISTORY:
9  *              21/07/98: Created
10  */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <limits.h>
15 #define NTOS_MODE_KERNEL
16 #include <ntos.h>
17 #include <internal/ob.h>
18 #include <internal/mm.h>
19 #include <internal/ke.h>
20 #include <internal/ps.h>
21 #include <internal/se.h>
22 #include <internal/id.h>
23 #include <napi/teb.h>
24 #include <internal/ldr.h>
25 #include <internal/port.h>
26 #include <napi/dbg.h>
27 #include <internal/dbg.h>
28 #include <internal/pool.h>
29 #include <roscfg.h>
30 #include <internal/se.h>
31 #include <internal/kd.h>
32 #include <internal/nls.h>
33
34 #define NDEBUG
35 #include <internal/debug.h>
36
37
38 /* GLOBALS ******************************************************************/
39
40 PEPROCESS EXPORTED PsInitialSystemProcess = NULL;
41 HANDLE SystemProcessHandle = NULL;
42
43 POBJECT_TYPE EXPORTED PsProcessType = NULL;
44
45 LIST_ENTRY PsProcessListHead;
46 static KSPIN_LOCK PsProcessListLock;
47 static ULONG PiNextProcessUniqueId = 0;
48
49 static GENERIC_MAPPING PiProcessMapping = {PROCESS_READ,
50                                            PROCESS_WRITE,
51                                            PROCESS_EXECUTE,
52                                            PROCESS_ALL_ACCESS};
53
54 #define MAX_PROCESS_NOTIFY_ROUTINE_COUNT    8
55
56 static PCREATE_PROCESS_NOTIFY_ROUTINE
57 PiProcessNotifyRoutine[MAX_PROCESS_NOTIFY_ROUTINE_COUNT];
58
59 typedef struct
60 {
61     WORK_QUEUE_ITEM WorkQueueItem;
62     KEVENT Event;
63     PEPROCESS Process;
64     BOOLEAN IsWorkerQueue;
65 } DEL_CONTEXT, *PDEL_CONTEXT;
66
67 /* FUNCTIONS *****************************************************************/
68
69 PEPROCESS
70 PsGetNextProcess(PEPROCESS OldProcess)
71 {
72    KIRQL oldIrql;
73    PEPROCESS NextProcess;
74    NTSTATUS Status;
75    
76    if (OldProcess == NULL)
77      {
78         return(PsInitialSystemProcess);
79      }
80    
81    KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
82    if (OldProcess->ProcessListEntry.Flink == &PsProcessListHead)
83      {
84         NextProcess = CONTAINING_RECORD(PsProcessListHead.Flink,
85                                         EPROCESS,
86                                         ProcessListEntry);
87      }
88    else
89      {
90         NextProcess = CONTAINING_RECORD(OldProcess->ProcessListEntry.Flink,
91                                         EPROCESS,
92                                         ProcessListEntry);
93      }
94    Status = ObReferenceObjectByPointer(NextProcess,
95                                        PROCESS_ALL_ACCESS,
96                                        PsProcessType,
97                                        KernelMode);   
98    KeReleaseSpinLock(&PsProcessListLock, oldIrql);
99    if (!NT_SUCCESS(Status))
100      {
101         CPRINT("PsGetNextProcess(): ObReferenceObjectByPointer failed\n");
102         KEBUGCHECK(0);
103      }
104    ObDereferenceObject(OldProcess);
105    
106    return(NextProcess);
107 }
108
109
110 NTSTATUS STDCALL 
111 _NtOpenProcessToken(IN  HANDLE          ProcessHandle,
112                    IN   ACCESS_MASK     DesiredAccess,
113                    OUT  PHANDLE         TokenHandle)
114 {
115    PACCESS_TOKEN Token;
116    NTSTATUS Status;
117   
118    Status = PsOpenTokenOfProcess(ProcessHandle,
119                                  &Token);
120    if (!NT_SUCCESS(Status))
121      {
122         return(Status);
123      }
124    Status = ObCreateHandle(PsGetCurrentProcess(),
125                            Token,
126                            DesiredAccess,
127                            FALSE,
128                            TokenHandle);
129    ObDereferenceObject(Token);
130    return(Status);
131 }
132
133
134 /*
135  * @implemented
136  */
137 NTSTATUS STDCALL 
138 NtOpenProcessToken(IN   HANDLE          ProcessHandle,
139                    IN   ACCESS_MASK     DesiredAccess,
140                    OUT  PHANDLE         TokenHandle)
141 {
142   return _NtOpenProcessToken(ProcessHandle, DesiredAccess, TokenHandle);
143 }
144
145
146 /*
147  * @implemented
148  */
149 PACCESS_TOKEN STDCALL
150 PsReferencePrimaryToken(PEPROCESS Process)
151 {
152    ObReferenceObjectByPointer(Process->Token,
153                               TOKEN_ALL_ACCESS,
154                               SepTokenObjectType,
155                               UserMode);
156    return(Process->Token);
157 }
158
159
160 NTSTATUS
161 PsOpenTokenOfProcess(HANDLE ProcessHandle,
162                      PACCESS_TOKEN* Token)
163 {
164    PEPROCESS Process;
165    NTSTATUS Status;
166    
167    Status = ObReferenceObjectByHandle(ProcessHandle,
168                                       PROCESS_QUERY_INFORMATION,
169                                       PsProcessType,
170                                       UserMode,
171                                       (PVOID*)&Process,
172                                       NULL);
173    if (!NT_SUCCESS(Status))
174      {
175         return(Status);
176      }
177    *Token = PsReferencePrimaryToken(Process);
178    ObDereferenceObject(Process);
179    return(STATUS_SUCCESS);
180 }
181
182
183 VOID 
184 PiKillMostProcesses(VOID)
185 {
186    KIRQL oldIrql;
187    PLIST_ENTRY current_entry;
188    PEPROCESS current;
189    
190    KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
191    
192    current_entry = PsProcessListHead.Flink;
193    while (current_entry != &PsProcessListHead)
194      {
195         current = CONTAINING_RECORD(current_entry, EPROCESS, 
196                                     ProcessListEntry);
197         current_entry = current_entry->Flink;
198         
199         if (current->UniqueProcessId != PsInitialSystemProcess->UniqueProcessId &&
200             current->UniqueProcessId != (ULONG)PsGetCurrentProcessId())
201           {
202              PiTerminateProcessThreads(current, STATUS_SUCCESS);
203           }
204      }
205    
206    KeReleaseSpinLock(&PsProcessListLock, oldIrql);
207 }
208
209
210 VOID
211 PsInitProcessManagment(VOID)
212 {
213    PKPROCESS KProcess;
214    KIRQL oldIrql;
215    NTSTATUS Status;
216    
217    /*
218     * Register the process object type
219     */
220    
221    PsProcessType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
222
223    PsProcessType->Tag = TAG('P', 'R', 'O', 'C');
224    PsProcessType->TotalObjects = 0;
225    PsProcessType->TotalHandles = 0;
226    PsProcessType->MaxObjects = ULONG_MAX;
227    PsProcessType->MaxHandles = ULONG_MAX;
228    PsProcessType->PagedPoolCharge = 0;
229    PsProcessType->NonpagedPoolCharge = sizeof(EPROCESS);
230    PsProcessType->Mapping = &PiProcessMapping;
231    PsProcessType->Dump = NULL;
232    PsProcessType->Open = NULL;
233    PsProcessType->Close = NULL;
234    PsProcessType->Delete = PiDeleteProcess;
235    PsProcessType->Parse = NULL;
236    PsProcessType->Security = NULL;
237    PsProcessType->QueryName = NULL;
238    PsProcessType->OkayToClose = NULL;
239    PsProcessType->Create = NULL;
240    PsProcessType->DuplicationNotify = NULL;
241    
242    RtlInitUnicodeStringFromLiteral(&PsProcessType->TypeName, L"Process");
243    
244    InitializeListHead(&PsProcessListHead);
245    KeInitializeSpinLock(&PsProcessListLock);
246    
247    /*
248     * Initialize the system process
249     */
250    Status = ObRosCreateObject(NULL,
251                            PROCESS_ALL_ACCESS,
252                            NULL,
253                            PsProcessType,
254                            (PVOID*)&PsInitialSystemProcess);
255    if (!NT_SUCCESS(Status))
256      {
257         return;
258      }
259    
260    /* System threads may run on any processor. */
261    PsInitialSystemProcess->Pcb.Affinity = 0xFFFFFFFF;
262    PsInitialSystemProcess->Pcb.IopmOffset = 0xffff;
263    PsInitialSystemProcess->Pcb.LdtDescriptor[0] = 0;
264    PsInitialSystemProcess->Pcb.LdtDescriptor[1] = 0;
265    PsInitialSystemProcess->Pcb.BasePriority = PROCESS_PRIO_NORMAL;
266    KeInitializeDispatcherHeader(&PsInitialSystemProcess->Pcb.DispatcherHeader,
267                                 InternalProcessType,
268                                 sizeof(EPROCESS),
269                                 FALSE);
270    KProcess = &PsInitialSystemProcess->Pcb;
271    
272    MmInitializeAddressSpace(PsInitialSystemProcess,
273                             &PsInitialSystemProcess->AddressSpace);
274    ObCreateHandleTable(NULL,FALSE,PsInitialSystemProcess);
275    KProcess->DirectoryTableBase = 
276      (LARGE_INTEGER)(LONGLONG)(ULONG)MmGetPageDirectory();
277    PsInitialSystemProcess->UniqueProcessId = 
278      InterlockedIncrement((LONG *)&PiNextProcessUniqueId);
279    PsInitialSystemProcess->Win32WindowStation = (HANDLE)0;
280    PsInitialSystemProcess->Win32Desktop = (HANDLE)0;
281    
282    KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
283    InsertHeadList(&PsProcessListHead, 
284                   &PsInitialSystemProcess->ProcessListEntry);
285    InitializeListHead(&PsInitialSystemProcess->ThreadListHead);
286    KeReleaseSpinLock(&PsProcessListLock, oldIrql);
287    
288    strcpy(PsInitialSystemProcess->ImageFileName, "SYSTEM");
289
290    SepCreateSystemProcessToken(PsInitialSystemProcess);
291
292    ObCreateHandle(PsInitialSystemProcess,
293                   PsInitialSystemProcess,
294                   PROCESS_ALL_ACCESS,
295                   FALSE,
296                   &SystemProcessHandle);
297 }
298
299 VOID STDCALL
300 PiDeleteProcessWorker(PVOID pContext)
301 {
302   KIRQL oldIrql;
303   ULONG i;
304   PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine[MAX_PROCESS_NOTIFY_ROUTINE_COUNT];
305   ULONG NotifyRoutineCount;
306   PDEL_CONTEXT Context;
307   PEPROCESS CurrentProcess;
308   PEPROCESS Process;
309
310   Context = (PDEL_CONTEXT)pContext;
311   Process = Context->Process;
312   CurrentProcess = PsGetCurrentProcess();
313
314   DPRINT("PiDeleteProcess(ObjectBody %x)\n",Process);
315
316   if (CurrentProcess != Process)
317     {
318       KeAttachProcess(Process);
319     }
320
321   /* Terminate Win32 Process */
322   PsTerminateWin32Process (Process);
323
324   KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
325   NotifyRoutineCount = 0;
326   for (i = 0; i < MAX_PROCESS_NOTIFY_ROUTINE_COUNT; i++)
327     {
328       if (PiProcessNotifyRoutine[i])
329         {
330           NotifyRoutine[NotifyRoutineCount++] = PiProcessNotifyRoutine[i];
331         }
332     }
333   RemoveEntryList(&Process->ProcessListEntry);
334   KeReleaseSpinLock(&PsProcessListLock, oldIrql);
335
336   for (i = 0;i < NotifyRoutineCount; i++)
337     {
338       /* must be called below DISPATCH_LVL */
339       NotifyRoutine[i](Process->InheritedFromUniqueProcessId,
340                        (HANDLE)Process->UniqueProcessId,
341                        FALSE);
342     }
343
344   /* KDB hook */
345   KDB_DELETEPROCESS_HOOK(Process);
346
347   ObDereferenceObject(Process->Token);
348   ObDeleteHandleTable(Process);
349
350   if (CurrentProcess != Process)
351     {
352       KeDetachProcess();
353     }
354
355   MmReleaseMmInfo(Process);
356   if (Context->IsWorkerQueue)
357     {
358       KeSetEvent(&Context->Event, IO_NO_INCREMENT, FALSE);
359     }
360 }
361
362 VOID STDCALL 
363 PiDeleteProcess(PVOID ObjectBody)
364 {
365   DEL_CONTEXT Context;
366
367   Context.Process = (PEPROCESS)ObjectBody;
368
369   if (PsGetCurrentProcess() == Context.Process || PsGetCurrentThread()->OldProcess == NULL)
370     {
371       Context.IsWorkerQueue = FALSE;
372       PiDeleteProcessWorker(&Context);
373     }
374   else
375     {
376       Context.IsWorkerQueue = TRUE;
377       KeInitializeEvent(&Context.Event, NotificationEvent, FALSE);
378       ExInitializeWorkItem (&Context.WorkQueueItem, PiDeleteProcessWorker, &Context);
379       ExQueueWorkItem(&Context.WorkQueueItem, HyperCriticalWorkQueue);
380       if (KeReadStateEvent(&Context.Event) == 0)
381         {
382           KeWaitForSingleObject(&Context.Event, Executive, KernelMode, FALSE, NULL);
383         }
384     }
385 }
386
387 static NTSTATUS
388 PsCreatePeb(HANDLE ProcessHandle,
389             PEPROCESS Process,
390             PVOID ImageBase)
391 {
392   ULONG PebSize;
393   PPEB Peb;
394   LARGE_INTEGER SectionOffset;
395   ULONG ViewSize;
396   PVOID TableBase;
397   NTSTATUS Status;
398
399   /* Allocate the Process Environment Block (PEB) */
400   Peb = (PPEB)PEB_BASE;
401   PebSize = PAGE_SIZE;
402   Status = NtAllocateVirtualMemory(ProcessHandle,
403                                    (PVOID*)&Peb,
404                                    0,
405                                    &PebSize,
406                                    MEM_RESERVE | MEM_COMMIT,
407                                    PAGE_READWRITE);
408   if (!NT_SUCCESS(Status))
409     {
410       DPRINT1("NtAllocateVirtualMemory() failed (Status %lx)\n", Status);
411       return(Status);
412     }
413   DPRINT("Peb %p  PebSize %lu\n", Peb, PebSize);
414
415   ViewSize = 0;
416   SectionOffset.QuadPart = 0LL;
417   TableBase = NULL;
418   Status = MmMapViewOfSection(NlsSectionObject,
419                               Process,
420                               &TableBase,
421                               0,
422                               0,
423                               &SectionOffset,
424                               &ViewSize,
425                               ViewShare,
426                               MEM_TOP_DOWN,
427                               PAGE_READONLY);
428   if (!NT_SUCCESS(Status))
429     {
430       DPRINT1("MmMapViewOfSection() failed (Status %lx)\n", Status);
431       return(Status);
432     }
433   DPRINT("TableBase %p  ViewSize %lx\n", TableBase, ViewSize);
434
435   KeAttachProcess(Process);
436
437   /* Initialize the PEB */
438   RtlZeroMemory(Peb, sizeof(PEB));
439   Peb->ImageBaseAddress = ImageBase;
440
441   Peb->OSMajorVersion = 4;
442   Peb->OSMinorVersion = 0;
443   Peb->OSBuildNumber = 0;
444   Peb->OSPlatformId = 2; //VER_PLATFORM_WIN32_NT;
445
446   Peb->AnsiCodePageData = TableBase + NlsAnsiTableOffset;
447   Peb->OemCodePageData = TableBase + NlsOemTableOffset;
448   Peb->UnicodeCaseTableData = TableBase + NlsUnicodeTableOffset;
449
450   Process->Peb = Peb;
451   KeDetachProcess();
452
453   DPRINT("PsCreatePeb: Peb created at %p\n", Peb);
454
455   return(STATUS_SUCCESS);
456 }
457
458
459 PKPROCESS
460 KeGetCurrentProcess(VOID)
461 /*
462  * FUNCTION: Returns a pointer to the current process
463  */
464 {
465   return(&(PsGetCurrentProcess()->Pcb));
466 }
467
468 /*
469  * @implemented
470  */
471 HANDLE STDCALL
472 PsGetCurrentProcessId(VOID)
473 {
474   return((HANDLE)PsGetCurrentProcess()->UniqueProcessId);
475 }
476
477 /*
478  * FUNCTION: Returns a pointer to the current process
479  *
480  * @implemented
481  */
482 PEPROCESS STDCALL
483 IoGetCurrentProcess(VOID)
484 {
485    if (PsGetCurrentThread() == NULL || 
486        PsGetCurrentThread()->ThreadsProcess == NULL)
487      {
488         return(PsInitialSystemProcess);
489      }
490    else
491      {
492         return(PsGetCurrentThread()->ThreadsProcess);
493      }
494 }
495
496 /*
497  * @implemented
498  */
499 NTSTATUS STDCALL
500 PsCreateSystemProcess(PHANDLE ProcessHandle,
501                       ACCESS_MASK DesiredAccess,
502                       POBJECT_ATTRIBUTES ObjectAttributes)
503 {
504    return NtCreateProcess(ProcessHandle,
505                           DesiredAccess,
506                           ObjectAttributes,
507                           SystemProcessHandle,
508                           FALSE,
509                           NULL,
510                           NULL,
511                           NULL);
512 }
513
514 NTSTATUS STDCALL
515 NtCreateProcess(OUT PHANDLE ProcessHandle,
516                 IN ACCESS_MASK DesiredAccess,
517                 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
518                 IN HANDLE ParentProcessHandle,
519                 IN BOOLEAN InheritObjectTable,
520                 IN HANDLE SectionHandle OPTIONAL,
521                 IN HANDLE DebugPortHandle OPTIONAL,
522                 IN HANDLE ExceptionPortHandle OPTIONAL)
523 /*
524  * FUNCTION: Creates a process.
525  * ARGUMENTS:
526  *        ProcessHandle (OUT) = Caller supplied storage for the resulting 
527  *                              handle
528  *        DesiredAccess = Specifies the allowed or desired access to the 
529  *                        process can be a combination of 
530  *                        STANDARD_RIGHTS_REQUIRED| ..  
531  *        ObjectAttribute = Initialized attributes for the object, contains 
532  *                          the rootdirectory and the filename
533  *        ParentProcess = Handle to the parent process.
534  *        InheritObjectTable = Specifies to inherit the objects of the parent 
535  *                             process if true.
536  *        SectionHandle = Handle to a section object to back the image file
537  *        DebugPort = Handle to a DebugPort if NULL the system default debug 
538  *                    port will be used.
539  *        ExceptionPort = Handle to a exception port. 
540  * REMARKS:
541  *        This function maps to the win32 CreateProcess. 
542  * RETURNS: Status
543  */
544 {
545    PEPROCESS Process;
546    PEPROCESS ParentProcess;
547    PKPROCESS KProcess;
548    NTSTATUS Status;
549    KIRQL oldIrql;
550    PVOID LdrStartupAddr;
551    PVOID ImageBase;
552    PEPORT DebugPort;
553    PEPORT ExceptionPort;
554    PVOID BaseAddress;
555    PMEMORY_AREA MemoryArea;
556    ULONG i;
557    PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine[MAX_PROCESS_NOTIFY_ROUTINE_COUNT];
558    ULONG NotifyRoutineCount;
559
560    DPRINT("NtCreateProcess(ObjectAttributes %x)\n",ObjectAttributes);
561
562    Status = ObReferenceObjectByHandle(ParentProcessHandle,
563                                       PROCESS_CREATE_PROCESS,
564                                       PsProcessType,
565                                       ExGetPreviousMode(),
566                                       (PVOID*)&ParentProcess,
567                                       NULL);
568    if (!NT_SUCCESS(Status))
569      {
570         DPRINT("NtCreateProcess() = %x\n",Status);
571         return(Status);
572      }
573
574    Status = ObRosCreateObject(ProcessHandle,
575                            DesiredAccess,
576                            ObjectAttributes,
577                            PsProcessType,
578                            (PVOID*)&Process);
579    if (!NT_SUCCESS(Status))
580      {
581         ObDereferenceObject(ParentProcess);
582         DPRINT("ObRosCreateObject() = %x\n",Status);
583         return(Status);
584      }
585
586    KeInitializeDispatcherHeader(&Process->Pcb.DispatcherHeader,
587                                 InternalProcessType,
588                                 sizeof(EPROCESS),
589                                 FALSE);
590    KProcess = &Process->Pcb;
591    /* Inherit parent process's affinity. */
592    KProcess->Affinity = ParentProcess->Pcb.Affinity;
593    KProcess->BasePriority = PROCESS_PRIO_NORMAL;
594    KProcess->IopmOffset = 0xffff;
595    KProcess->LdtDescriptor[0] = 0;
596    KProcess->LdtDescriptor[1] = 0;
597    MmInitializeAddressSpace(Process,
598                             &Process->AddressSpace);
599    Process->UniqueProcessId = InterlockedIncrement((LONG *)&PiNextProcessUniqueId);
600    Process->InheritedFromUniqueProcessId = 
601      (HANDLE)ParentProcess->UniqueProcessId;
602    ObCreateHandleTable(ParentProcess,
603                        InheritObjectTable,
604                        Process);
605    MmCopyMmInfo(ParentProcess, Process);
606    if (ParentProcess->Win32WindowStation != (HANDLE)0)
607      {
608        /* Always duplicate the process window station. */
609        Process->Win32WindowStation = 0;
610        Status = ObDuplicateObject(ParentProcess,
611                                   Process,
612                                   ParentProcess->Win32WindowStation,
613                                   &Process->Win32WindowStation,
614                                   0,
615                                   FALSE,
616                                   DUPLICATE_SAME_ACCESS);
617        if (!NT_SUCCESS(Status))
618          {
619            KEBUGCHECK(0);
620          }
621      }
622    else
623      {
624        Process->Win32WindowStation = (HANDLE)0;
625      }
626    if (ParentProcess->Win32Desktop != (HANDLE)0)
627      {
628        /* Always duplicate the process window station. */
629        Process->Win32Desktop = 0;
630        Status = ObDuplicateObject(ParentProcess,
631                                   Process,
632                                   ParentProcess->Win32Desktop,
633                                   &Process->Win32Desktop,
634                                   0,
635                                   FALSE,
636                                   DUPLICATE_SAME_ACCESS);
637        if (!NT_SUCCESS(Status))
638          {
639            KEBUGCHECK(0);
640          }
641      }
642    else
643      {
644        Process->Win32Desktop = (HANDLE)0;
645      }
646
647    KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
648    NotifyRoutineCount = 0;
649    for (i = 0; i < MAX_PROCESS_NOTIFY_ROUTINE_COUNT; i++)
650    {
651       if (PiProcessNotifyRoutine[i])
652       {
653          NotifyRoutine[NotifyRoutineCount++] = PiProcessNotifyRoutine[i];   
654       }
655    }
656    InsertHeadList(&PsProcessListHead, &Process->ProcessListEntry);
657    InitializeListHead(&Process->ThreadListHead);
658    KeReleaseSpinLock(&PsProcessListLock, oldIrql);
659
660    for (i = 0;i < NotifyRoutineCount; i++)
661    {
662       //must be called below DISPATCH_LVL
663       NotifyRoutine[i](Process->InheritedFromUniqueProcessId,
664                        (HANDLE)Process->UniqueProcessId,
665                        TRUE);
666    }
667
668    Process->Pcb.State = PROCESS_STATE_ACTIVE;
669    
670    /*
671     * Add the debug port
672     */
673    if (DebugPortHandle != NULL)
674      {
675         Status = ObReferenceObjectByHandle(DebugPortHandle,
676                                            PORT_ALL_ACCESS,
677                                            ExPortType,
678                                            UserMode,
679                                            (PVOID*)&DebugPort,
680                                            NULL);   
681         if (!NT_SUCCESS(Status))
682           {
683              ObDereferenceObject(Process);
684              ObDereferenceObject(ParentProcess);
685              ZwClose(*ProcessHandle);
686              *ProcessHandle = NULL;
687              return(Status);
688           }
689         Process->DebugPort = DebugPort;
690      }
691         
692    /*
693     * Add the exception port
694     */
695    if (ExceptionPortHandle != NULL)
696      {
697         Status = ObReferenceObjectByHandle(ExceptionPortHandle,
698                                            PORT_ALL_ACCESS,
699                                            ExPortType,
700                                            UserMode,
701                                            (PVOID*)&ExceptionPort,
702                                            NULL);   
703         if (!NT_SUCCESS(Status))
704           {
705              ObDereferenceObject(Process);
706              ObDereferenceObject(ParentProcess);
707              ZwClose(*ProcessHandle);
708              *ProcessHandle = NULL;
709              return(Status);
710           }
711         Process->ExceptionPort = ExceptionPort;
712      }
713    
714    /*
715     * Now we have created the process proper
716     */
717
718    MmLockAddressSpace(&Process->AddressSpace);
719
720    /* Protect the highest 64KB of the process address space */
721    BaseAddress = MmUserProbeAddress;
722    Status = MmCreateMemoryArea(Process,
723                                &Process->AddressSpace,
724                                MEMORY_AREA_NO_ACCESS,
725                                &BaseAddress,
726                                0x10000,
727                                PAGE_NOACCESS,
728                                &MemoryArea,
729                                FALSE,
730                                FALSE);
731    if (!NT_SUCCESS(Status))
732      {
733         MmUnlockAddressSpace(&Process->AddressSpace);
734         DPRINT1("Failed to protect the highest 64KB of the process address space\n");
735         KEBUGCHECK(0);
736      }
737
738    /* Protect the lowest 64KB of the process address space */
739 #if 0
740    BaseAddress = (PVOID)0x00000000;
741    Status = MmCreateMemoryArea(Process,
742                                &Process->AddressSpace,
743                                MEMORY_AREA_NO_ACCESS,
744                                &BaseAddress,
745                                0x10000,
746                                PAGE_NOACCESS,
747                                &MemoryArea,
748                                FALSE,
749                                FALSE);
750    if (!NT_SUCCESS(Status))
751      {
752         MmUnlockAddressSpace(&Process->AddressSpace);
753         DPRINT1("Failed to protect the lowest 64KB of the process address space\n");
754         KEBUGCHECK(0);
755      }
756 #endif
757
758    /* Protect the 60KB above the shared user page */
759    BaseAddress = (PVOID)USER_SHARED_DATA + PAGE_SIZE;
760    Status = MmCreateMemoryArea(Process,
761                                &Process->AddressSpace,
762                                MEMORY_AREA_NO_ACCESS,
763                                &BaseAddress,
764                                0x10000 - PAGE_SIZE,
765                                PAGE_NOACCESS,
766                                &MemoryArea,
767                                FALSE,
768                                FALSE);
769    if (!NT_SUCCESS(Status))
770      {
771         MmUnlockAddressSpace(&Process->AddressSpace);
772         DPRINT1("Failed to protect the memory above the shared user page\n");
773         KEBUGCHECK(0);
774      }
775
776    /* Create the shared data page */
777    BaseAddress = (PVOID)USER_SHARED_DATA;
778    Status = MmCreateMemoryArea(Process,
779                                &Process->AddressSpace,
780                                MEMORY_AREA_SHARED_DATA,
781                                &BaseAddress,
782                                PAGE_SIZE,
783                                PAGE_READONLY,
784                                &MemoryArea,
785                                FALSE,
786                                FALSE);
787    MmUnlockAddressSpace(&Process->AddressSpace);
788    if (!NT_SUCCESS(Status))
789      {
790         DPRINT1("Failed to create shared data page\n");
791         KEBUGCHECK(0);
792      }
793
794    /*
795     * Map ntdll
796     */
797    Status = LdrpMapSystemDll(*ProcessHandle,
798                              &LdrStartupAddr);
799    if (!NT_SUCCESS(Status))
800      {
801         DbgPrint("LdrpMapSystemDll failed (Status %x)\n", Status);
802         ObDereferenceObject(Process);
803         ObDereferenceObject(ParentProcess);
804         return(Status);
805      }
806    
807    /*
808     * Map the process image
809     */
810    if (SectionHandle != NULL)
811      {
812         DPRINT("Mapping process image\n");
813         Status = LdrpMapImage(*ProcessHandle,
814                               SectionHandle,
815                               &ImageBase);
816         if (!NT_SUCCESS(Status))
817           {
818              DbgPrint("LdrpMapImage failed (Status %x)\n", Status);
819              ObDereferenceObject(Process);
820              ObDereferenceObject(ParentProcess);
821              return(Status);
822           }
823      }
824    else
825      {
826         ImageBase = NULL;
827      }
828    
829   /*
830    * Duplicate the token
831    */
832   Status = SepInitializeNewProcess(Process, ParentProcess);
833   if (!NT_SUCCESS(Status))
834     {
835        DbgPrint("SepInitializeNewProcess failed (Status %x)\n", Status);
836        ObDereferenceObject(Process);
837        ObDereferenceObject(ParentProcess);
838        return(Status);
839     }
840
841    /*
842     * 
843     */
844    DPRINT("Creating PEB\n");
845    Status = PsCreatePeb(*ProcessHandle,
846                         Process,
847                         ImageBase);
848    if (!NT_SUCCESS(Status))
849      {
850         DbgPrint("NtCreateProcess() Peb creation failed: Status %x\n",Status);
851         ObDereferenceObject(Process);
852         ObDereferenceObject(ParentProcess);
853         ZwClose(*ProcessHandle);
854         *ProcessHandle = NULL;
855         return(Status);
856      }
857    
858    /*
859     * Maybe send a message to the creator process's debugger
860     */
861 #if 0
862    if (ParentProcess->DebugPort != NULL)
863      {
864         LPC_DBG_MESSAGE Message;
865         HANDLE FileHandle;
866         
867         ObCreateHandle(NULL, // Debugger Process
868                        NULL, // SectionHandle
869                        FILE_ALL_ACCESS,
870                        FALSE,
871                        &FileHandle);
872         
873         Message.Header.MessageSize = sizeof(LPC_DBG_MESSAGE);
874         Message.Header.DataSize = sizeof(LPC_DBG_MESSAGE) -
875           sizeof(LPC_MESSAGE);
876         Message.Type = DBG_EVENT_CREATE_PROCESS;
877         Message.Data.CreateProcess.FileHandle = FileHandle;
878         Message.Data.CreateProcess.Base = ImageBase;
879         Message.Data.CreateProcess.EntryPoint = NULL; //
880         
881         Status = LpcSendDebugMessagePort(ParentProcess->DebugPort,
882                                          &Message);
883      }
884 #endif
885    
886    ObDereferenceObject(Process);
887    ObDereferenceObject(ParentProcess);
888    return(STATUS_SUCCESS);
889 }
890
891
892 /*
893  * @unimplemented
894  */
895 NTSTATUS STDCALL
896 NtOpenProcess(OUT PHANDLE           ProcessHandle,
897               IN  ACCESS_MASK       DesiredAccess,
898               IN  POBJECT_ATTRIBUTES  ObjectAttributes,
899               IN  PCLIENT_ID        ClientId)
900 {
901    DPRINT("NtOpenProcess(ProcessHandle %x, DesiredAccess %x, "
902           "ObjectAttributes %x, ClientId %x { UniP %d, UniT %d })\n",
903           ProcessHandle, DesiredAccess, ObjectAttributes, ClientId,
904           ClientId->UniqueProcess, ClientId->UniqueThread);
905           
906    
907    /*
908     * Not sure of the exact semantics 
909     */
910    if (ObjectAttributes != NULL && ObjectAttributes->ObjectName != NULL &&
911        ObjectAttributes->ObjectName->Buffer != NULL)
912      {
913         NTSTATUS Status;
914         PEPROCESS Process;
915                 
916         Status = ObReferenceObjectByName(ObjectAttributes->ObjectName,
917                                          ObjectAttributes->Attributes,
918                                          NULL,
919                                          DesiredAccess,
920                                          PsProcessType,
921                                          UserMode,
922                                          NULL,
923                                          (PVOID*)&Process);
924         if (Status != STATUS_SUCCESS)
925           {
926              return(Status);
927           }
928         
929         Status = ObCreateHandle(PsGetCurrentProcess(),
930                                 Process,
931                                 DesiredAccess,
932                                 FALSE,
933                                 ProcessHandle);
934         ObDereferenceObject(Process);
935    
936         return(Status);
937      }
938    else
939      {
940         KIRQL oldIrql;
941         PLIST_ENTRY current_entry;
942         PEPROCESS current;
943         NTSTATUS Status;
944         
945         KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
946         current_entry = PsProcessListHead.Flink;
947         while (current_entry != &PsProcessListHead)
948           {
949              current = CONTAINING_RECORD(current_entry, EPROCESS, 
950                                          ProcessListEntry);
951              if (current->UniqueProcessId == (ULONG)ClientId->UniqueProcess)
952                {
953                   ObReferenceObjectByPointer(current,
954                                              DesiredAccess,
955                                              PsProcessType,
956                                              UserMode);
957                   KeReleaseSpinLock(&PsProcessListLock, oldIrql);
958                   Status = ObCreateHandle(PsGetCurrentProcess(),
959                                           current,
960                                           DesiredAccess,
961                                           FALSE,
962                                           ProcessHandle);
963                   ObDereferenceObject(current);
964                   DPRINT("*ProcessHandle %x\n", ProcessHandle);
965                   DPRINT("NtOpenProcess() = %x\n", Status);
966                   return(Status);
967                }
968              current_entry = current_entry->Flink;
969           }
970         KeReleaseSpinLock(&PsProcessListLock, oldIrql);
971         DPRINT("NtOpenProcess() = STATUS_UNSUCCESSFUL\n");
972         return(STATUS_UNSUCCESSFUL);
973      }
974    return(STATUS_UNSUCCESSFUL);
975 }
976
977
978 /*
979  * @unimplemented
980  */
981 NTSTATUS STDCALL
982 NtQueryInformationProcess(IN  HANDLE ProcessHandle,
983                           IN  CINT ProcessInformationClass,
984                           OUT PVOID ProcessInformation,
985                           IN  ULONG ProcessInformationLength,
986                           OUT PULONG ReturnLength OPTIONAL)
987 {
988    PEPROCESS Process;
989    NTSTATUS Status;
990
991    /*
992     * TODO: Here we should probably check that ProcessInformationLength
993     * bytes indeed are writable at address ProcessInformation.
994     */
995
996    Status = ObReferenceObjectByHandle(ProcessHandle,
997                                       PROCESS_SET_INFORMATION,
998                                       PsProcessType,
999                                       UserMode,
1000                                       (PVOID*)&Process,
1001                                       NULL);
1002    if (Status != STATUS_SUCCESS)
1003      {
1004         return(Status);
1005      }
1006
1007    switch (ProcessInformationClass)
1008      {
1009       case ProcessBasicInformation:
1010         if (ProcessInformationLength != sizeof(PROCESS_BASIC_INFORMATION))
1011         {
1012           Status = STATUS_INFO_LENGTH_MISMATCH;
1013         }
1014         else
1015         {
1016           PPROCESS_BASIC_INFORMATION ProcessBasicInformationP =
1017             (PPROCESS_BASIC_INFORMATION)ProcessInformation;
1018           ProcessBasicInformationP->ExitStatus = Process->ExitStatus;
1019           ProcessBasicInformationP->PebBaseAddress = Process->Peb;
1020           ProcessBasicInformationP->AffinityMask = Process->Pcb.Affinity;
1021           ProcessBasicInformationP->UniqueProcessId =
1022             Process->UniqueProcessId;
1023           ProcessBasicInformationP->InheritedFromUniqueProcessId =
1024             (ULONG)Process->InheritedFromUniqueProcessId;
1025
1026           if (ReturnLength)
1027           {
1028             *ReturnLength = sizeof(PROCESS_BASIC_INFORMATION);
1029           }
1030         }
1031         break;
1032
1033       case ProcessQuotaLimits:
1034       case ProcessIoCounters:
1035       case ProcessTimes:
1036       case ProcessDebugPort:
1037       case ProcessLdtInformation:
1038       case ProcessWorkingSetWatch:
1039       case ProcessWx86Information:
1040       case ProcessHandleCount:
1041       case ProcessSessionInformation:
1042       case ProcessWow64Information:
1043         Status = STATUS_NOT_IMPLEMENTED;
1044         break;
1045
1046       case ProcessVmCounters:
1047         if (ProcessInformationLength != sizeof(VM_COUNTERS))
1048         {
1049           Status = STATUS_INFO_LENGTH_MISMATCH;
1050         }
1051         else
1052         {
1053           PVM_COUNTERS pOut = (PVM_COUNTERS)ProcessInformation;
1054           pOut->PeakVirtualSize            = Process->PeakVirtualSize;
1055           /*
1056            * Here we should probably use VirtualSize.LowPart, but due to
1057            * incompatibilities in current headers (no unnamed union),
1058            * I opted for cast.
1059            */
1060           pOut->VirtualSize                = (ULONG)Process->VirtualSize.QuadPart;
1061           pOut->PageFaultCount             = Process->Vm.PageFaultCount;
1062           pOut->PeakWorkingSetSize         = Process->Vm.PeakWorkingSetSize;
1063           pOut->WorkingSetSize             = Process->Vm.WorkingSetSize;
1064           pOut->QuotaPeakPagedPoolUsage    = Process->QuotaPeakPoolUsage[0]; // TODO: Verify!
1065           pOut->QuotaPagedPoolUsage        = Process->QuotaPoolUsage[0];     // TODO: Verify!
1066           pOut->QuotaPeakNonPagedPoolUsage = Process->QuotaPeakPoolUsage[1]; // TODO: Verify!
1067           pOut->QuotaNonPagedPoolUsage     = Process->QuotaPoolUsage[1];     // TODO: Verify!
1068           pOut->PagefileUsage              = Process->PagefileUsage;
1069           pOut->PeakPagefileUsage          = Process->PeakPagefileUsage;
1070
1071           if (ReturnLength)
1072           {
1073             *ReturnLength = sizeof(VM_COUNTERS);
1074           }
1075         }
1076         break;
1077
1078       case ProcessDefaultHardErrorMode:
1079         if (ProcessInformationLength != sizeof(ULONG))
1080         {
1081           Status = STATUS_INFO_LENGTH_MISMATCH;
1082         }
1083         else
1084         {
1085           PULONG HardErrMode = (PULONG)ProcessInformation;
1086           *HardErrMode = Process->DefaultHardErrorProcessing;
1087
1088           if (ReturnLength)
1089           {
1090             *ReturnLength = sizeof(ULONG);
1091           }
1092         }
1093         break;
1094
1095       case ProcessPriorityBoost:
1096         if (ProcessInformationLength != sizeof(ULONG))
1097         {
1098           Status = STATUS_INFO_LENGTH_MISMATCH;
1099         }
1100         else
1101         {
1102           PULONG BoostEnabled = (PULONG)ProcessInformation;
1103           *BoostEnabled = Process->Pcb.DisableBoost ? FALSE : TRUE;
1104
1105           if (ReturnLength)
1106           {
1107             *ReturnLength = sizeof(ULONG);
1108           }
1109         }
1110         break;
1111
1112       case ProcessDeviceMap:
1113         Status = STATUS_NOT_IMPLEMENTED;
1114         break;
1115
1116       case ProcessPriorityClass:
1117         if (ProcessInformationLength != sizeof(USHORT))
1118         {
1119           Status = STATUS_INFO_LENGTH_MISMATCH;
1120         }
1121         else
1122         {
1123           PUSHORT Priority = (PUSHORT)ProcessInformation;
1124           *Priority = Process->PriorityClass;
1125
1126           if (ReturnLength)
1127           {
1128             *ReturnLength = sizeof(USHORT);
1129           }
1130         }
1131         break;
1132
1133       /*
1134        * Note: The following 10 information classes are verified to not be
1135        * implemented on NT, and do indeed return STATUS_INVALID_INFO_CLASS;
1136        */
1137       case ProcessBasePriority:
1138       case ProcessRaisePriority:
1139       case ProcessExceptionPort:
1140       case ProcessAccessToken:
1141       case ProcessLdtSize:
1142       case ProcessIoPortHandlers:
1143       case ProcessUserModeIOPL:
1144       case ProcessEnableAlignmentFaultFixup:
1145       case ProcessAffinityMask:
1146       case ProcessForegroundInformation:
1147       default:
1148         Status = STATUS_INVALID_INFO_CLASS;
1149      }
1150    ObDereferenceObject(Process);
1151    return(Status);
1152 }
1153
1154
1155 NTSTATUS
1156 PspAssignPrimaryToken(PEPROCESS Process,
1157                       HANDLE TokenHandle)
1158 {
1159    PACCESS_TOKEN Token;
1160    PACCESS_TOKEN OldToken;
1161    NTSTATUS Status;
1162    
1163    Status = ObReferenceObjectByHandle(TokenHandle,
1164                                       0,
1165                                       SepTokenObjectType,
1166                                       UserMode,
1167                                       (PVOID*)&Token,
1168                                       NULL);
1169    if (!NT_SUCCESS(Status))
1170      {
1171         return(Status);
1172      }
1173    Status = SeExchangePrimaryToken(Process, Token, &OldToken);
1174    if (NT_SUCCESS(Status))
1175      {
1176         ObDereferenceObject(OldToken);
1177      }
1178    ObDereferenceObject(Token);
1179    return(Status);
1180 }
1181
1182 /*
1183  * @unimplemented
1184  */
1185 NTSTATUS STDCALL
1186 NtSetInformationProcess(IN HANDLE ProcessHandle,
1187                         IN CINT ProcessInformationClass,
1188                         IN PVOID ProcessInformation,
1189                         IN ULONG ProcessInformationLength)
1190 {
1191    PEPROCESS Process;
1192    NTSTATUS Status;
1193    PHANDLE ProcessAccessTokenP;
1194    
1195    Status = ObReferenceObjectByHandle(ProcessHandle,
1196                                       PROCESS_SET_INFORMATION,
1197                                       PsProcessType,
1198                                       UserMode,
1199                                       (PVOID*)&Process,
1200                                       NULL);
1201    if (!NT_SUCCESS(Status))
1202      {
1203         return(Status);
1204      }
1205
1206    switch (ProcessInformationClass)
1207      {
1208       case ProcessQuotaLimits:
1209       case ProcessBasePriority:
1210       case ProcessRaisePriority:
1211       case ProcessDebugPort:
1212       case ProcessExceptionPort:
1213         Status = STATUS_NOT_IMPLEMENTED;
1214         break;
1215
1216       case ProcessAccessToken:
1217         ProcessAccessTokenP = (PHANDLE)ProcessInformation;
1218         Status = PspAssignPrimaryToken(Process, *ProcessAccessTokenP);
1219         break;
1220         
1221       case ProcessImageFileName:
1222         memcpy(Process->ImageFileName, ProcessInformation, 8);
1223         Status = STATUS_SUCCESS;
1224         break;
1225         
1226       case ProcessLdtInformation:
1227       case ProcessLdtSize:
1228       case ProcessDefaultHardErrorMode:
1229       case ProcessIoPortHandlers:
1230       case ProcessWorkingSetWatch:
1231       case ProcessUserModeIOPL:
1232       case ProcessEnableAlignmentFaultFixup:
1233       case ProcessPriorityClass:
1234       case ProcessAffinityMask:
1235         Status = STATUS_NOT_IMPLEMENTED;
1236         break;
1237
1238       case ProcessBasicInformation:
1239       case ProcessIoCounters:
1240       case ProcessTimes:
1241       case ProcessPooledUsageAndLimits:
1242       case ProcessWx86Information:
1243       case ProcessHandleCount:
1244       case ProcessWow64Information:
1245       default:
1246         Status = STATUS_INVALID_INFO_CLASS;
1247
1248      case ProcessDesktop:
1249        Process->Win32Desktop = *(PHANDLE)ProcessInformation;
1250        Status = STATUS_SUCCESS;
1251        break;
1252      }
1253    ObDereferenceObject(Process);
1254    return(Status);
1255 }
1256
1257
1258 /**********************************************************************
1259  * NAME                                                 INTERNAL
1260  *      PiQuerySystemProcessInformation
1261  *
1262  * DESCRIPTION
1263  *      Compute the size of a process+thread snapshot as 
1264  *      expected by NtQuerySystemInformation.
1265  *
1266  * RETURN VALUE
1267  *      0 on error; otherwise the size, in bytes of the buffer
1268  *      required to write a full snapshot.
1269  *
1270  * NOTE
1271  *      We assume (sizeof (PVOID) == sizeof (ULONG)) holds.
1272  */
1273 NTSTATUS
1274 PiQuerySystemProcessInformation(PVOID Buffer,
1275                                 ULONG Size,
1276                                 PULONG ReqSize)
1277 {
1278    return STATUS_NOT_IMPLEMENTED;
1279
1280 #if 0
1281         KIRQL           OldIrql;
1282         PLIST_ENTRY     CurrentEntryP;
1283         PEPROCESS       CurrentP;
1284         PLIST_ENTRY     CurrentEntryT;
1285         PETHREAD        CurrentT;
1286         
1287         ULONG           RequiredSize = 0L;
1288         BOOLEAN         SizeOnly = FALSE;
1289
1290         ULONG           SpiSize = 0L;
1291         
1292         PSYSTEM_PROCESS_INFORMATION     pInfoP = (PSYSTEM_PROCESS_INFORMATION) SnapshotBuffer;
1293         PSYSTEM_PROCESS_INFORMATION     pInfoPLast = NULL;
1294         PSYSTEM_THREAD_INFO             pInfoT = NULL;
1295         
1296
1297    /* Lock the process list. */
1298    KeAcquireSpinLock(&PsProcessListLock,
1299                      &OldIrql);
1300
1301         /*
1302          * Scan the process list. Since the
1303          * list is circular, the guard is false
1304          * after the last process.
1305          */
1306         for (   CurrentEntryP = PsProcessListHead.Flink;
1307                 (CurrentEntryP != & PsProcessListHead);
1308                 CurrentEntryP = CurrentEntryP->Flink
1309                 )
1310         {
1311                 /*
1312                  * Compute how much space is
1313                  * occupied in the snapshot
1314                  * by adding this process info.
1315                  * (at least one thread).
1316                  */
1317                 SpiSizeCurrent = sizeof (SYSTEM_PROCESS_INFORMATION);
1318                 RequiredSize += SpiSizeCurrent;
1319                 /*
1320                  * Do not write process data in the
1321                  * buffer if it is too small.
1322                  */
1323                 if (TRUE == SizeOnly) continue;
1324                 /*
1325                  * Check if the buffer can contain
1326                  * the full snapshot.
1327                  */
1328                 if (Size < RequiredSize)
1329                 {
1330                         SizeOnly = TRUE;
1331                         continue;
1332                 }
1333                 /* 
1334                  * Get a reference to the 
1335                  * process descriptor we are
1336                  * handling.
1337                  */
1338                 CurrentP = CONTAINING_RECORD(
1339                                 CurrentEntryP,
1340                                 EPROCESS, 
1341                                 ProcessListEntry
1342                                 );
1343                 /*
1344                  * Write process data in the buffer.
1345                  */
1346                 RtlZeroMemory (pInfoP, sizeof (SYSTEM_PROCESS_INFORMATION));
1347                 /* PROCESS */
1348                 pInfoP->ThreadCount = 0L;
1349                 pInfoP->ProcessId = CurrentP->UniqueProcessId;
1350                 RtlInitUnicodeString (
1351                         & pInfoP->Name,
1352                         CurrentP->ImageFileName
1353                         );
1354                 /* THREAD */
1355                 for (   pInfoT = & CurrentP->ThreadSysInfo [0],
1356                         CurrentEntryT = CurrentP->ThreadListHead.Flink;
1357                         
1358                         (CurrentEntryT != & CurrentP->ThreadListHead);
1359                         
1360                         pInfoT = & CurrentP->ThreadSysInfo [pInfoP->ThreadCount],
1361                         CurrentEntryT = CurrentEntryT->Flink
1362                         )
1363                 {
1364                         /*
1365                          * Recalculate the size of the
1366                          * information block.
1367                          */
1368                         if (0 < pInfoP->ThreadCount)
1369                         {
1370                                 RequiredSize += sizeof (SYSTEM_THREAD_INFORMATION);
1371                         }
1372                         /*
1373                          * Do not write thread data in the
1374                          * buffer if it is too small.
1375                          */
1376                         if (TRUE == SizeOnly) continue;
1377                         /*
1378                          * Check if the buffer can contain
1379                          * the full snapshot.
1380                          */
1381                         if (Size < RequiredSize)
1382                         {
1383                                 SizeOnly = TRUE;
1384                                 continue;
1385                         }
1386                         /* 
1387                          * Get a reference to the 
1388                          * thread descriptor we are
1389                          * handling.
1390                          */
1391                         CurrentT = CONTAINING_RECORD(
1392                                         CurrentEntryT,
1393                                         KTHREAD, 
1394                                         Tcb.ThreadListEntry
1395                                         );
1396                         /*
1397                          * Write thread data.
1398                          */
1399                         RtlZeroMemory (
1400                                 pInfoT,
1401                                 sizeof (SYSTEM_THREAD_INFORMATION)
1402                                 );
1403                         pInfoT->KernelTime      = CurrentT-> ;  /* TIME */
1404                         pInfoT->UserTime        = CurrentT-> ;  /* TIME */
1405                         pInfoT->CreateTime      = CurrentT-> ;  /* TIME */
1406                         pInfoT->TickCount       = CurrentT-> ;  /* ULONG */
1407                         pInfoT->StartEIP        = CurrentT-> ;  /* ULONG */
1408                         pInfoT->ClientId        = CurrentT-> ;  /* CLIENT_ID */
1409                         pInfoT->ClientId        = CurrentT-> ;  /* CLIENT_ID */
1410                         pInfoT->DynamicPriority = CurrentT-> ;  /* ULONG */
1411                         pInfoT->BasePriority    = CurrentT-> ;  /* ULONG */
1412                         pInfoT->nSwitches       = CurrentT-> ;  /* ULONG */
1413                         pInfoT->State           = CurrentT-> ;  /* DWORD */
1414                         pInfoT->WaitReason      = CurrentT-> ;  /* KWAIT_REASON */
1415                         /*
1416                          * Count the number of threads 
1417                          * this process has.
1418                          */
1419                         ++ pInfoP->ThreadCount;
1420                 }
1421                 /*
1422                  * Save the size of information
1423                  * stored in the buffer for the
1424                  * current process.
1425                  */
1426                 pInfoP->RelativeOffset = SpiSize;
1427                 /*
1428                  * Save a reference to the last
1429                  * valid information block.
1430                  */
1431                 pInfoPLast = pInfoP;
1432                 /*
1433                  * Compute the offset of the 
1434                  * SYSTEM_PROCESS_INFORMATION
1435                  * descriptor in the snapshot 
1436                  * buffer for the next process.
1437                  */
1438                 (ULONG) pInfoP += SpiSize;
1439         }
1440         /*
1441          * Unlock the process list.
1442          */
1443         KeReleaseSpinLock (
1444                 & PsProcessListLock,
1445                 OldIrql
1446                 );
1447         /*
1448          * Return the proper error status code,
1449          * if the buffer was too small.
1450          */
1451         if (TRUE == SizeOnly)
1452         {
1453                 if (NULL != RequiredSize)
1454                 {
1455                         *pRequiredSize = RequiredSize;
1456                 }
1457                 return STATUS_INFO_LENGTH_MISMATCH;
1458         }
1459         /*
1460          * Mark the end of the snapshot.
1461          */
1462         pInfoP->RelativeOffset = 0L;
1463         /* OK */        
1464         return STATUS_SUCCESS;
1465 #endif
1466 }
1467
1468 /*
1469  * @implemented
1470  */
1471 LARGE_INTEGER STDCALL
1472 PsGetProcessExitTime(VOID)
1473 {
1474   LARGE_INTEGER Li;
1475   Li.QuadPart = PsGetCurrentProcess()->ExitTime.QuadPart;
1476   return Li;
1477 }
1478
1479 /*
1480  * @implemented
1481  */
1482 BOOLEAN STDCALL
1483 PsIsThreadTerminating(IN PETHREAD Thread)
1484 {
1485   return(Thread->DeadThread);
1486 }
1487
1488
1489 /*
1490  * @implemented
1491  */
1492 NTSTATUS STDCALL
1493 PsLookupProcessByProcessId(IN PVOID ProcessId,
1494                            OUT PEPROCESS *Process)
1495 {
1496   KIRQL oldIrql;
1497   PLIST_ENTRY current_entry;
1498   PEPROCESS current;
1499
1500   KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
1501
1502   current_entry = PsProcessListHead.Flink;
1503   while (current_entry != &PsProcessListHead)
1504     {
1505       current = CONTAINING_RECORD(current_entry,
1506                                   EPROCESS,
1507                                   ProcessListEntry);
1508       if (current->UniqueProcessId == (ULONG)ProcessId)
1509         {
1510           *Process = current;
1511           ObReferenceObject(current);
1512           KeReleaseSpinLock(&PsProcessListLock, oldIrql);
1513           return(STATUS_SUCCESS);
1514         }
1515       current_entry = current_entry->Flink;
1516     }
1517
1518   KeReleaseSpinLock(&PsProcessListLock, oldIrql);
1519
1520   return(STATUS_INVALID_PARAMETER);
1521 }
1522
1523
1524 /*
1525  * @implemented
1526  */
1527 NTSTATUS STDCALL
1528 PsSetCreateProcessNotifyRoutine(IN PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,
1529                                 IN BOOLEAN Remove)
1530 {
1531   KIRQL oldIrql;
1532   ULONG i;
1533
1534   KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
1535
1536   if (Remove)
1537   {
1538      for(i=0;i<MAX_PROCESS_NOTIFY_ROUTINE_COUNT;i++)
1539      {
1540         if ((PVOID)PiProcessNotifyRoutine[i] == (PVOID)NotifyRoutine)
1541         {
1542            PiProcessNotifyRoutine[i] = NULL;
1543            break;
1544         }
1545      }
1546
1547      KeReleaseSpinLock(&PsProcessListLock, oldIrql);
1548      return(STATUS_SUCCESS);
1549   }
1550
1551   /*insert*/
1552   for(i=0;i<MAX_PROCESS_NOTIFY_ROUTINE_COUNT;i++)
1553   {
1554      if (PiProcessNotifyRoutine[i] == NULL)
1555      {
1556         PiProcessNotifyRoutine[i] = NotifyRoutine;
1557         break;
1558      }
1559   }
1560
1561   KeReleaseSpinLock(&PsProcessListLock, oldIrql);
1562
1563   if (i == MAX_PROCESS_NOTIFY_ROUTINE_COUNT)
1564   {
1565      return STATUS_INSUFFICIENT_RESOURCES;
1566   }
1567
1568   return STATUS_SUCCESS;
1569 }
1570
1571 /* EOF */