branch update for HEAD-2003050101
[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 #include <ddk/ntddk.h>
16 #include <internal/ob.h>
17 #include <internal/mm.h>
18 #include <internal/ke.h>
19 #include <internal/ps.h>
20 #include <internal/se.h>
21 #include <internal/id.h>
22 #include <napi/teb.h>
23 #include <internal/ldr.h>
24 #include <internal/port.h>
25 #include <napi/dbg.h>
26 #include <internal/dbg.h>
27 #include <internal/pool.h>
28 #include <roscfg.h>
29 #include <internal/se.h>
30 #include <internal/kd.h>
31
32 #define NDEBUG
33 #include <internal/debug.h>
34
35 /* GLOBALS ******************************************************************/
36
37 PEPROCESS EXPORTED PsInitialSystemProcess = NULL;
38 HANDLE SystemProcessHandle = NULL;
39
40 POBJECT_TYPE EXPORTED PsProcessType = NULL;
41
42 LIST_ENTRY PsProcessListHead;
43 static KSPIN_LOCK PsProcessListLock;
44 static ULONG PiNextProcessUniqueId = 0;
45
46 static GENERIC_MAPPING PiProcessMapping = {PROCESS_READ,
47                                            PROCESS_WRITE,
48                                            PROCESS_EXECUTE,
49                                            PROCESS_ALL_ACCESS};
50
51 #define MAX_PROCESS_NOTIFY_ROUTINE_COUNT    8
52
53 #ifndef LIBCAPTIVE
54 static ULONG PiProcessNotifyRoutineCount = 0;
55 static PCREATE_PROCESS_NOTIFY_ROUTINE
56 PiProcessNotifyRoutine[MAX_PROCESS_NOTIFY_ROUTINE_COUNT];
57 #endif /* LIBCAPTIVE */
58
59 /* FUNCTIONS *****************************************************************/
60
61 #ifndef LIBCAPTIVE
62
63 PEPROCESS 
64 PsGetNextProcess(PEPROCESS OldProcess)
65 {
66    KIRQL oldIrql;
67    PEPROCESS NextProcess;
68    NTSTATUS Status;
69    
70    if (OldProcess == NULL)
71      {
72         return(PsInitialSystemProcess);
73      }
74    
75    KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
76    if (OldProcess->ProcessListEntry.Flink == &PsProcessListHead)
77      {
78         NextProcess = CONTAINING_RECORD(PsProcessListHead.Flink,
79                                         EPROCESS,
80                                         ProcessListEntry);
81      }
82    else
83      {
84         NextProcess = CONTAINING_RECORD(OldProcess->ProcessListEntry.Flink,
85                                         EPROCESS,
86                                         ProcessListEntry);
87      }
88    KeReleaseSpinLock(&PsProcessListLock, oldIrql);
89    Status = ObReferenceObjectByPointer(NextProcess,
90                                        PROCESS_ALL_ACCESS,
91                                        PsProcessType,
92                                        KernelMode);   
93    if (!NT_SUCCESS(Status))
94      {
95         CPRINT("PsGetNextProcess(): ObReferenceObjectByPointer failed\n");
96         KeBugCheck(0);
97      }
98    ObDereferenceObject(OldProcess);
99    
100    return(NextProcess);
101 }
102
103
104 NTSTATUS STDCALL 
105 _NtOpenProcessToken(IN  HANDLE          ProcessHandle,
106                    IN   ACCESS_MASK     DesiredAccess,
107                    OUT  PHANDLE         TokenHandle)
108 {
109    PACCESS_TOKEN Token;
110    NTSTATUS Status;
111   
112    Status = PsOpenTokenOfProcess(ProcessHandle,
113                                  &Token);
114    if (!NT_SUCCESS(Status))
115      {
116         return(Status);
117      }
118    Status = ObCreateHandle(PsGetCurrentProcess(),
119                            Token,
120                            DesiredAccess,
121                            FALSE,
122                            TokenHandle);
123    ObDereferenceObject(Token);
124    return(Status);
125 }
126
127
128 NTSTATUS STDCALL 
129 NtOpenProcessToken(IN   HANDLE          ProcessHandle,
130                    IN   ACCESS_MASK     DesiredAccess,
131                    OUT  PHANDLE         TokenHandle)
132 {
133   return _NtOpenProcessToken(ProcessHandle, DesiredAccess, TokenHandle);
134 }
135
136 #endif /* LIBCAPTIVE */
137
138 PACCESS_TOKEN STDCALL
139 PsReferencePrimaryToken(PEPROCESS Process)
140 {
141    ObReferenceObjectByPointer(Process->Token,
142                               TOKEN_ALL_ACCESS,
143                               SepTokenObjectType,
144                               UserMode);
145    return(Process->Token);
146 }
147
148 #ifndef LIBCAPTIVE
149
150 NTSTATUS
151 PsOpenTokenOfProcess(HANDLE ProcessHandle,
152                      PACCESS_TOKEN* Token)
153 {
154    PEPROCESS Process;
155    NTSTATUS Status;
156    
157    Status = ObReferenceObjectByHandle(ProcessHandle,
158                                       PROCESS_QUERY_INFORMATION,
159                                       PsProcessType,
160                                       UserMode,
161                                       (PVOID*)&Process,
162                                       NULL);
163    if (!NT_SUCCESS(Status))
164      {
165         return(Status);
166      }
167    *Token = PsReferencePrimaryToken(Process);
168    ObDereferenceObject(Process);
169    return(STATUS_SUCCESS);
170 }
171
172
173 VOID 
174 PiKillMostProcesses(VOID)
175 {
176    KIRQL oldIrql;
177    PLIST_ENTRY current_entry;
178    PEPROCESS current;
179    
180    KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
181    
182    current_entry = PsProcessListHead.Flink;
183    while (current_entry != &PsProcessListHead)
184      {
185         current = CONTAINING_RECORD(current_entry, EPROCESS, 
186                                     ProcessListEntry);
187         current_entry = current_entry->Flink;
188         
189         if (current->UniqueProcessId != PsInitialSystemProcess->UniqueProcessId &&
190             current->UniqueProcessId != (ULONG)PsGetCurrentProcessId())
191           {
192              PiTerminateProcessThreads(current, STATUS_SUCCESS);
193           }
194      }
195    
196    KeReleaseSpinLock(&PsProcessListLock, oldIrql);
197 }
198
199 #endif /* LIBCAPTIVE */
200
201 VOID
202 PsInitProcessManagment(VOID)
203 {
204    PKPROCESS KProcess;
205    KIRQL oldIrql;
206    NTSTATUS Status;
207    
208    /*
209     * Register the process object type
210     */
211    
212    PsProcessType = ExAllocatePool(NonPagedPool, sizeof(OBJECT_TYPE));
213
214    PsProcessType->Tag = TAG('P', 'R', 'O', 'C');
215    PsProcessType->TotalObjects = 0;
216    PsProcessType->TotalHandles = 0;
217    PsProcessType->MaxObjects = ULONG_MAX;
218    PsProcessType->MaxHandles = ULONG_MAX;
219    PsProcessType->PagedPoolCharge = 0;
220    PsProcessType->NonpagedPoolCharge = sizeof(EPROCESS)
221 #ifdef LIBCAPTIVE
222          /* Need to present 0-terminated string "System"
223           * from KPROCESS up to PAGE_SIZE offset
224           * for ext2fsd.sys V0.10A debug.c/Ext2GetProcessNameOffset()
225           */
226          +strlen("System")+1/* 0-terminator */;
227 #endif /* LIBCAPTIVE */
228          ;
229    PsProcessType->Mapping = &PiProcessMapping;
230    PsProcessType->Dump = NULL;
231    PsProcessType->Open = NULL;
232    PsProcessType->Close = NULL;
233 #ifndef LIBCAPTIVE
234    PsProcessType->Delete = PiDeleteProcess;
235 #else
236    PsProcessType->Delete = NULL;        /* never Delete PsInitialSystemProcess */
237 #endif /* LIBCAPTIVE */
238    PsProcessType->Parse = NULL;
239    PsProcessType->Security = NULL;
240    PsProcessType->QueryName = NULL;
241    PsProcessType->OkayToClose = NULL;
242    PsProcessType->Create = NULL;
243    PsProcessType->DuplicationNotify = NULL;
244    
245    RtlInitUnicodeStringFromLiteral(&PsProcessType->TypeName, REACTOS_UCS2(L"Process"));
246    
247    InitializeListHead(&PsProcessListHead);
248    KeInitializeSpinLock(&PsProcessListLock);
249    
250    /*
251     * Initialize the system process
252     */
253    Status = ObCreateObject(NULL,
254                            PROCESS_ALL_ACCESS,
255                            NULL,
256                            PsProcessType,
257                            (PVOID*)&PsInitialSystemProcess);
258    if (!NT_SUCCESS(Status))
259      {
260         return;
261      }
262    
263 #ifdef LIBCAPTIVE
264    /* Need to present 0-terminated string "System"
265     * from KPROCESS up to PAGE_SIZE offset
266     * for ext2fsd.sys V0.10A debug.c/Ext2GetProcessNameOffset()
267     */
268    strcpy(((char *)PsInitialSystemProcess) +strlen("System")+1/* 0-terminator */,"System");
269 #endif /* LIBCAPTIVE */
270
271    /* System threads may run on any processor. */
272    PsInitialSystemProcess->Pcb.Affinity = 0xFFFFFFFF;
273    PsInitialSystemProcess->Pcb.BasePriority = PROCESS_PRIO_NORMAL;
274 #ifndef LIBCAPTIVE
275    KeInitializeDispatcherHeader(&PsInitialSystemProcess->Pcb.DispatcherHeader,
276                                 InternalProcessType,
277                                 sizeof(EPROCESS),
278                                 FALSE);
279 #endif /* LIBCAPTIVE */
280    KProcess = &PsInitialSystemProcess->Pcb;
281    
282 #ifndef LIBCAPTIVE
283    MmInitializeAddressSpace(PsInitialSystemProcess,
284                             &PsInitialSystemProcess->AddressSpace);
285 #endif /* LIBCAPTIVE */
286    ObCreateHandleTable(NULL,FALSE,PsInitialSystemProcess);
287 #ifndef LIBCAPTIVE
288    KProcess->DirectoryTableBase = 
289      (LARGE_INTEGER)(LONGLONG)(ULONG)MmGetPageDirectory();
290 #endif /* LIBCAPTIVE */
291    PsInitialSystemProcess->UniqueProcessId = 
292      InterlockedIncrement((LONG *)&PiNextProcessUniqueId);
293    PsInitialSystemProcess->Win32WindowStation = (HANDLE)0;
294    PsInitialSystemProcess->Win32Desktop = (HANDLE)0;
295    
296    KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
297    InsertHeadList(&PsProcessListHead, 
298                   &PsInitialSystemProcess->ProcessListEntry);
299    InitializeListHead(&PsInitialSystemProcess->ThreadListHead);
300    KeReleaseSpinLock(&PsProcessListLock, oldIrql);
301    
302    strcpy(PsInitialSystemProcess->ImageFileName, "SYSTEM");
303
304    SepCreateSystemProcessToken(PsInitialSystemProcess);
305
306    ObCreateHandle(PsInitialSystemProcess,
307                   PsInitialSystemProcess,
308                   PROCESS_ALL_ACCESS,
309                   FALSE,
310                   &SystemProcessHandle);
311 }
312
313 #ifndef LIBCAPTIVE
314
315 VOID STDCALL
316 PiDeleteProcess(PVOID ObjectBody)
317 {
318   KIRQL oldIrql;
319   PEPROCESS Process;
320   ULONG i;
321
322   DPRINT("PiDeleteProcess(ObjectBody %x)\n",ObjectBody);
323
324   Process = (PEPROCESS)ObjectBody;
325   KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
326   for (i = 0; i < PiProcessNotifyRoutineCount; i++)
327     {
328       PiProcessNotifyRoutine[i](Process->InheritedFromUniqueProcessId,
329                                 (HANDLE)Process->UniqueProcessId,
330                                 FALSE);
331     }
332    RemoveEntryList(&Process->ProcessListEntry);
333    KeReleaseSpinLock(&PsProcessListLock, oldIrql);
334
335    /* KDB hook */
336    KDB_DELETEPROCESS_HOOK(Process);
337
338    ObDereferenceObject(Process->Token);
339    ObDeleteHandleTable(Process);
340
341    (VOID)MmReleaseMmInfo(Process);
342 }
343
344
345 static NTSTATUS
346 PsCreatePeb(HANDLE ProcessHandle,
347             PVOID ImageBase,
348             PVOID* RPeb)
349 {
350    NTSTATUS Status;
351    PVOID PebBase;
352    ULONG PebSize;
353    PEB Peb;
354    ULONG BytesWritten;
355    
356    memset(&Peb, 0, sizeof(Peb));
357    Peb.ImageBaseAddress = ImageBase;
358    
359    PebBase = (PVOID)PEB_BASE;
360    PebSize = 0x1000;
361    Status = NtAllocateVirtualMemory(ProcessHandle,
362                                     &PebBase,
363                                     0,
364                                     &PebSize,
365                                     MEM_RESERVE | MEM_COMMIT,
366                                     PAGE_READWRITE);
367    if (!NT_SUCCESS(Status))
368      {
369         return(Status);
370      }
371    
372    NtWriteVirtualMemory(ProcessHandle,
373                         (PVOID)PEB_BASE,
374                         &Peb,
375                         sizeof(Peb),
376                         &BytesWritten);
377
378    DPRINT("PsCreatePeb: Peb created at %x\n", PebBase);
379    
380    *RPeb = PebBase;
381    
382    return(STATUS_SUCCESS);
383 }
384
385
386 PKPROCESS
387 KeGetCurrentProcess(VOID)
388 /*
389  * FUNCTION: Returns a pointer to the current process
390  */
391 {
392    return(&(PsGetCurrentProcess()->Pcb));
393 }
394
395 HANDLE STDCALL
396 PsGetCurrentProcessId(VOID)
397 {
398    return((HANDLE)PsGetCurrentProcess()->UniqueProcessId);
399 }
400
401 #endif /* LIBCAPTIVE */
402
403 /*
404  * FUNCTION: Returns a pointer to the current process
405  */
406 PEPROCESS STDCALL
407 IoGetCurrentProcess(VOID)
408 {
409 #ifndef LIBCAPTIVE
410    if (PsGetCurrentThread() == NULL || 
411        PsGetCurrentThread()->ThreadsProcess == NULL)
412      {
413 #endif /* LIBCAPTIVE */
414         return(PsInitialSystemProcess);
415 #ifndef LIBCAPTIVE
416      }
417    else
418      {
419         return(PsGetCurrentThread()->ThreadsProcess);
420      }
421 #endif /* LIBCAPTIVE */
422 }
423
424 #ifndef LIBCAPTIVE
425
426 NTSTATUS STDCALL
427 PsCreateSystemProcess(PHANDLE ProcessHandle,
428                       ACCESS_MASK DesiredAccess,
429                       POBJECT_ATTRIBUTES ObjectAttributes)
430 {
431    return NtCreateProcess(ProcessHandle,
432                           DesiredAccess,
433                           ObjectAttributes,
434                           SystemProcessHandle,
435                           FALSE,
436                           NULL,
437                           NULL,
438                           NULL);
439 }
440
441 NTSTATUS STDCALL
442 NtCreateProcess(OUT PHANDLE ProcessHandle,
443                 IN ACCESS_MASK DesiredAccess,
444                 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
445                 IN HANDLE ParentProcessHandle,
446                 IN BOOLEAN InheritObjectTable,
447                 IN HANDLE SectionHandle OPTIONAL,
448                 IN HANDLE DebugPortHandle OPTIONAL,
449                 IN HANDLE ExceptionPortHandle OPTIONAL)
450 /*
451  * FUNCTION: Creates a process.
452  * ARGUMENTS:
453  *        ProcessHandle (OUT) = Caller supplied storage for the resulting 
454  *                              handle
455  *        DesiredAccess = Specifies the allowed or desired access to the 
456  *                        process can be a combination of 
457  *                        STANDARD_RIGHTS_REQUIRED| ..  
458  *        ObjectAttribute = Initialized attributes for the object, contains 
459  *                          the rootdirectory and the filename
460  *        ParentProcess = Handle to the parent process.
461  *        InheritObjectTable = Specifies to inherit the objects of the parent 
462  *                             process if true.
463  *        SectionHandle = Handle to a section object to back the image file
464  *        DebugPort = Handle to a DebugPort if NULL the system default debug 
465  *                    port will be used.
466  *        ExceptionPort = Handle to a exception port. 
467  * REMARKS:
468  *        This function maps to the win32 CreateProcess. 
469  * RETURNS: Status
470  */
471 {
472    PEPROCESS Process;
473    PEPROCESS ParentProcess;
474    PKPROCESS KProcess;
475    NTSTATUS Status;
476    KIRQL oldIrql;
477    PVOID LdrStartupAddr;
478    PVOID ImageBase;
479    PVOID Peb;
480    PEPORT DebugPort;
481    PEPORT ExceptionPort;
482    PVOID BaseAddress;
483    PMEMORY_AREA MemoryArea;
484    ULONG i;
485    
486    DPRINT("NtCreateProcess(ObjectAttributes %x)\n",ObjectAttributes);
487
488    Status = ObReferenceObjectByHandle(ParentProcessHandle,
489                                       PROCESS_CREATE_PROCESS,
490                                       PsProcessType,
491                                       ExGetPreviousMode(),
492                                       (PVOID*)&ParentProcess,
493                                       NULL);
494    if (!NT_SUCCESS(Status))
495      {
496         DPRINT("NtCreateProcess() = %x\n",Status);
497         return(Status);
498      }
499
500    Status = ObCreateObject(ProcessHandle,
501                            DesiredAccess,
502                            ObjectAttributes,
503                            PsProcessType,
504                            (PVOID*)&Process);
505    if (!NT_SUCCESS(Status))
506      {
507         ObDereferenceObject(ParentProcess);
508         DPRINT("ObCreateObject() = %x\n",Status);
509         return(Status);
510      }
511
512    KeInitializeDispatcherHeader(&Process->Pcb.DispatcherHeader,
513                                 InternalProcessType,
514                                 sizeof(EPROCESS),
515                                 FALSE);
516    KProcess = &Process->Pcb;
517    /* Inherit parent process's affinity. */
518    KProcess->Affinity = ParentProcess->Pcb.Affinity;
519    KProcess->BasePriority = PROCESS_PRIO_NORMAL;
520    MmInitializeAddressSpace(Process,
521                             &Process->AddressSpace);
522    Process->UniqueProcessId = InterlockedIncrement((LONG *)&PiNextProcessUniqueId);
523    Process->InheritedFromUniqueProcessId = 
524      (HANDLE)ParentProcess->UniqueProcessId;
525    ObCreateHandleTable(ParentProcess,
526                        InheritObjectTable,
527                        Process);
528    MmCopyMmInfo(ParentProcess, Process);
529    if (ParentProcess->Win32WindowStation != (HANDLE)0)
530      {
531        /* Always duplicate the process window station. */
532        Process->Win32WindowStation = 0;
533        Status = ObDuplicateObject(ParentProcess,
534                                   Process,
535                                   ParentProcess->Win32WindowStation,
536                                   &Process->Win32WindowStation,
537                                   0,
538                                   FALSE,
539                                   DUPLICATE_SAME_ACCESS);
540        if (!NT_SUCCESS(Status))
541          {
542            KeBugCheck(0);
543          }
544      }
545    else
546      {
547        Process->Win32WindowStation = (HANDLE)0;
548      }
549    if (ParentProcess->Win32Desktop != (HANDLE)0)
550      {
551        /* Always duplicate the process window station. */
552        Process->Win32Desktop = 0;
553        Status = ObDuplicateObject(ParentProcess,
554                                   Process,
555                                   ParentProcess->Win32Desktop,
556                                   &Process->Win32Desktop,
557                                   0,
558                                   FALSE,
559                                   DUPLICATE_SAME_ACCESS);
560        if (!NT_SUCCESS(Status))
561          {
562            KeBugCheck(0);
563          }
564      }
565    else
566      {
567        Process->Win32Desktop = (HANDLE)0;
568      }
569
570    KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
571    for (i = 0; i < PiProcessNotifyRoutineCount; i++)
572     {
573       PiProcessNotifyRoutine[i](Process->InheritedFromUniqueProcessId,
574                                 (HANDLE)Process->UniqueProcessId,
575                                 TRUE);
576     }
577    InsertHeadList(&PsProcessListHead, &Process->ProcessListEntry);
578    InitializeListHead(&Process->ThreadListHead);
579    KeReleaseSpinLock(&PsProcessListLock, oldIrql);
580    
581    Process->Pcb.State = PROCESS_STATE_ACTIVE;
582    
583    /*
584     * Add the debug port
585     */
586    if (DebugPortHandle != NULL)
587      {
588         Status = ObReferenceObjectByHandle(DebugPortHandle,
589                                            PORT_ALL_ACCESS,
590                                            ExPortType,
591                                            UserMode,
592                                            (PVOID*)&DebugPort,
593                                            NULL);   
594         if (!NT_SUCCESS(Status))
595           {
596              ObDereferenceObject(Process);
597              ObDereferenceObject(ParentProcess);
598              ZwClose(*ProcessHandle);
599              *ProcessHandle = NULL;
600              return(Status);
601           }
602         Process->DebugPort = DebugPort;
603      }
604         
605    /*
606     * Add the exception port
607     */
608    if (ExceptionPortHandle != NULL)
609      {
610         Status = ObReferenceObjectByHandle(ExceptionPortHandle,
611                                            PORT_ALL_ACCESS,
612                                            ExPortType,
613                                            UserMode,
614                                            (PVOID*)&ExceptionPort,
615                                            NULL);   
616         if (!NT_SUCCESS(Status))
617           {
618              ObDereferenceObject(Process);
619              ObDereferenceObject(ParentProcess);
620              ZwClose(*ProcessHandle);
621              *ProcessHandle = NULL;
622              return(Status);
623           }
624         Process->ExceptionPort = ExceptionPort;
625      }
626    
627    /*
628     * Now we have created the process proper
629     */
630    
631    /*
632     * Create the shared data page
633     */
634    MmLockAddressSpace(&Process->AddressSpace);
635    BaseAddress = (PVOID)USER_SHARED_DATA;
636    Status = MmCreateMemoryArea(Process,
637                                &Process->AddressSpace,
638                                MEMORY_AREA_SHARED_DATA,
639                                &BaseAddress,
640                                PAGE_SIZE,
641                                PAGE_READONLY,
642                                &MemoryArea,
643                                FALSE);
644    MmUnlockAddressSpace(&Process->AddressSpace);
645    if (!NT_SUCCESS(Status))
646      {
647         DPRINT1("Failed to create shared data page\n");
648         KeBugCheck(0);
649      }
650    
651    /*
652     * Map ntdll
653     */
654    Status = LdrpMapSystemDll(*ProcessHandle,
655                              &LdrStartupAddr);
656    if (!NT_SUCCESS(Status))
657      {
658         DbgPrint("LdrpMapSystemDll failed (Status %x)\n", Status);
659         ObDereferenceObject(Process);
660         ObDereferenceObject(ParentProcess);
661         return(Status);
662      }
663    
664    /*
665     * Map the process image
666     */
667    if (SectionHandle != NULL)
668      {
669         DPRINT("Mapping process image\n");
670         Status = LdrpMapImage(*ProcessHandle,
671                               SectionHandle,
672                               &ImageBase);
673         if (!NT_SUCCESS(Status))
674           {
675              DbgPrint("LdrpMapImage failed (Status %x)\n", Status);
676              ObDereferenceObject(Process);
677              ObDereferenceObject(ParentProcess);
678              return(Status);
679           }
680      }
681    else
682      {
683         ImageBase = NULL;
684      }
685    
686   /*
687    * Duplicate the token
688    */
689   Status = SepInitializeNewProcess(Process, ParentProcess);
690   if (!NT_SUCCESS(Status))
691     {
692        DbgPrint("SepInitializeNewProcess failed (Status %x)\n", Status);
693        ObDereferenceObject(Process);
694        ObDereferenceObject(ParentProcess);
695        return(Status);
696     }
697
698    /*
699     * 
700     */
701    DPRINT("Creating PEB\n");
702    Status = PsCreatePeb(*ProcessHandle,
703                         ImageBase,
704                         &Peb);
705    if (!NT_SUCCESS(Status))
706      {
707         DbgPrint("NtCreateProcess() Peb creation failed: Status %x\n",Status);
708         ObDereferenceObject(Process);
709         ObDereferenceObject(ParentProcess);
710         ZwClose(*ProcessHandle);
711         *ProcessHandle = NULL;
712         return(Status);
713      }
714    Process->Peb = Peb;
715    
716    /*
717     * Maybe send a message to the creator process's debugger
718     */
719 #if 0
720    if (ParentProcess->DebugPort != NULL)
721      {
722         LPC_DBG_MESSAGE Message;
723         HANDLE FileHandle;
724         
725         ObCreateHandle(NULL, // Debugger Process
726                        NULL, // SectionHandle
727                        FILE_ALL_ACCESS,
728                        FALSE,
729                        &FileHandle);
730         
731         Message.Header.MessageSize = sizeof(LPC_DBG_MESSAGE);
732         Message.Header.DataSize = sizeof(LPC_DBG_MESSAGE) -
733           sizeof(LPC_MESSAGE);
734         Message.Type = DBG_EVENT_CREATE_PROCESS;
735         Message.Data.CreateProcess.FileHandle = FileHandle;
736         Message.Data.CreateProcess.Base = ImageBase;
737         Message.Data.CreateProcess.EntryPoint = NULL; //
738         
739         Status = LpcSendDebugMessagePort(ParentProcess->DebugPort,
740                                          &Message);
741      }
742 #endif
743    
744    ObDereferenceObject(Process);
745    ObDereferenceObject(ParentProcess);
746    return(STATUS_SUCCESS);
747 }
748
749
750 NTSTATUS STDCALL
751 NtOpenProcess(OUT PHANDLE           ProcessHandle,
752               IN  ACCESS_MASK       DesiredAccess,
753               IN  POBJECT_ATTRIBUTES  ObjectAttributes,
754               IN  PCLIENT_ID        ClientId)
755 {
756    DPRINT("NtOpenProcess(ProcessHandle %x, DesiredAccess %x, "
757           "ObjectAttributes %x, ClientId %x { UniP %d, UniT %d })\n",
758           ProcessHandle, DesiredAccess, ObjectAttributes, ClientId,
759           ClientId->UniqueProcess, ClientId->UniqueThread);
760           
761    
762    /*
763     * Not sure of the exact semantics 
764     */
765    if (ObjectAttributes != NULL && ObjectAttributes->ObjectName != NULL &&
766        ObjectAttributes->ObjectName->Buffer != NULL)
767      {
768         NTSTATUS Status;
769         PEPROCESS Process;
770                 
771         Status = ObReferenceObjectByName(ObjectAttributes->ObjectName,
772                                          ObjectAttributes->Attributes,
773                                          NULL,
774                                          DesiredAccess,
775                                          PsProcessType,
776                                          UserMode,
777                                          NULL,
778                                          (PVOID*)&Process);
779         if (Status != STATUS_SUCCESS)
780           {
781              return(Status);
782           }
783         
784         Status = ObCreateHandle(PsGetCurrentProcess(),
785                                 Process,
786                                 DesiredAccess,
787                                 FALSE,
788                                 ProcessHandle);
789         ObDereferenceObject(Process);
790    
791         return(Status);
792      }
793    else
794      {
795         KIRQL oldIrql;
796         PLIST_ENTRY current_entry;
797         PEPROCESS current;
798         NTSTATUS Status;
799         
800         KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
801         current_entry = PsProcessListHead.Flink;
802         while (current_entry != &PsProcessListHead)
803           {
804              current = CONTAINING_RECORD(current_entry, EPROCESS, 
805                                          ProcessListEntry);
806              if (current->UniqueProcessId == (ULONG)ClientId->UniqueProcess)
807                {
808                   ObReferenceObjectByPointer(current,
809                                              DesiredAccess,
810                                              PsProcessType,
811                                              UserMode);
812                   KeReleaseSpinLock(&PsProcessListLock, oldIrql);
813                   Status = ObCreateHandle(PsGetCurrentProcess(),
814                                           current,
815                                           DesiredAccess,
816                                           FALSE,
817                                           ProcessHandle);
818                   ObDereferenceObject(current);
819                   DPRINT("*ProcessHandle %x\n", ProcessHandle);
820                   DPRINT("NtOpenProcess() = %x\n", Status);
821                   return(Status);
822                }
823              current_entry = current_entry->Flink;
824           }
825         KeReleaseSpinLock(&PsProcessListLock, oldIrql);
826         DPRINT("NtOpenProcess() = STATUS_UNSUCCESSFUL\n");
827         return(STATUS_UNSUCCESSFUL);
828      }
829    return(STATUS_UNSUCCESSFUL);
830 }
831
832
833 NTSTATUS STDCALL
834 NtQueryInformationProcess(IN  HANDLE ProcessHandle,
835                           IN  CINT ProcessInformationClass,
836                           OUT PVOID ProcessInformation,
837                           IN  ULONG ProcessInformationLength,
838                           OUT PULONG ReturnLength)
839 {
840    PEPROCESS Process;
841    NTSTATUS Status;
842    PPROCESS_BASIC_INFORMATION ProcessBasicInformationP;
843    
844    Status = ObReferenceObjectByHandle(ProcessHandle,
845                                       PROCESS_SET_INFORMATION,
846                                       PsProcessType,
847                                       UserMode,
848                                       (PVOID*)&Process,
849                                       NULL);
850    if (Status != STATUS_SUCCESS)
851      {
852         return(Status);
853      }
854    
855    switch (ProcessInformationClass)
856      {
857       case ProcessBasicInformation:
858         ProcessBasicInformationP = (PPROCESS_BASIC_INFORMATION)
859           ProcessInformation;
860         ProcessBasicInformationP->ExitStatus = Process->ExitStatus;
861         ProcessBasicInformationP->PebBaseAddress = Process->Peb;
862         ProcessBasicInformationP->AffinityMask = Process->Pcb.Affinity;
863         ProcessBasicInformationP->UniqueProcessId =
864           Process->UniqueProcessId;
865         ProcessBasicInformationP->InheritedFromUniqueProcessId =
866           (ULONG)Process->InheritedFromUniqueProcessId;
867         Status = STATUS_SUCCESS;
868         break;
869         
870       case ProcessQuotaLimits:
871       case ProcessIoCounters:
872       case ProcessVmCounters:
873       case ProcessTimes:
874       case ProcessDebugPort:
875       case ProcessLdtInformation:
876         Status = STATUS_NOT_IMPLEMENTED;
877         break;
878         
879       case ProcessDefaultHardErrorMode:
880         *((PULONG)ProcessInformation) = Process->DefaultHardErrorProcessing;
881         break;
882         
883       case ProcessWorkingSetWatch:
884         Status = STATUS_NOT_IMPLEMENTED;
885         break;
886
887       case ProcessWx86Information:
888       case ProcessHandleCount:
889       case ProcessPriorityBoost:
890       case ProcessDeviceMap:
891       case ProcessSessionInformation:
892       case ProcessWow64Information:
893         Status = STATUS_NOT_IMPLEMENTED;
894         break;
895         
896       case ProcessBasePriority:
897       case ProcessRaisePriority:
898       case ProcessExceptionPort:
899       case ProcessAccessToken:
900       case ProcessLdtSize:
901       case ProcessIoPortHandlers:
902       case ProcessUserModeIOPL:
903       case ProcessEnableAlignmentFaultFixup:
904       case ProcessPriorityClass:
905       case ProcessAffinityMask:
906       case ProcessForegroundInformation:
907       default:
908         Status = STATUS_INVALID_INFO_CLASS;
909      }
910    ObDereferenceObject(Process);
911    return(Status);
912 }
913
914 NTSTATUS
915 PspAssignPrimaryToken(PEPROCESS Process,
916                       HANDLE TokenHandle)
917 {
918    PACCESS_TOKEN Token;
919    PACCESS_TOKEN OldToken;
920    NTSTATUS Status;
921    
922    Status = ObReferenceObjectByHandle(TokenHandle,
923                                       0,
924                                       SepTokenObjectType,
925                                       UserMode,
926                                       (PVOID*)&Token,
927                                       NULL);
928    if (!NT_SUCCESS(Status))
929      {
930         return(Status);
931      }
932    Status = SeExchangePrimaryToken(Process, Token, &OldToken);
933    if (NT_SUCCESS(Status))
934      {
935         ObDereferenceObject(OldToken);
936      }
937    ObDereferenceObject(Token);
938    return(Status);
939 }
940
941 NTSTATUS STDCALL
942 NtSetInformationProcess(IN HANDLE ProcessHandle,
943                         IN CINT ProcessInformationClass,
944                         IN PVOID ProcessInformation,
945                         IN ULONG ProcessInformationLength)
946 {
947    PEPROCESS Process;
948    NTSTATUS Status;
949    PHANDLE ProcessAccessTokenP;
950    
951    Status = ObReferenceObjectByHandle(ProcessHandle,
952                                       PROCESS_SET_INFORMATION,
953                                       PsProcessType,
954                                       UserMode,
955                                       (PVOID*)&Process,
956                                       NULL);
957    if (!NT_SUCCESS(Status))
958      {
959         return(Status);
960      }
961
962    switch (ProcessInformationClass)
963      {
964       case ProcessQuotaLimits:
965       case ProcessBasePriority:
966       case ProcessRaisePriority:
967       case ProcessDebugPort:
968       case ProcessExceptionPort:
969         Status = STATUS_NOT_IMPLEMENTED;
970         break;
971
972       case ProcessAccessToken:
973         ProcessAccessTokenP = (PHANDLE)ProcessInformation;
974         Status = PspAssignPrimaryToken(Process, *ProcessAccessTokenP);
975         break;
976         
977       case ProcessImageFileName:
978         memcpy(Process->ImageFileName, ProcessInformation, 8);
979         Status = STATUS_SUCCESS;
980         break;
981         
982       case ProcessLdtInformation:
983       case ProcessLdtSize:
984       case ProcessDefaultHardErrorMode:
985       case ProcessIoPortHandlers:
986       case ProcessWorkingSetWatch:
987       case ProcessUserModeIOPL:
988       case ProcessEnableAlignmentFaultFixup:
989       case ProcessPriorityClass:
990       case ProcessAffinityMask:
991         Status = STATUS_NOT_IMPLEMENTED;
992         break;
993
994       case ProcessBasicInformation:
995       case ProcessIoCounters:
996       case ProcessVmCounters:
997       case ProcessTimes:
998       case ProcessPooledUsageAndLimits:
999       case ProcessWx86Information:
1000       case ProcessHandleCount:
1001       case ProcessWow64Information:
1002       default:
1003         Status = STATUS_INVALID_INFO_CLASS;
1004
1005      case ProcessDesktop:
1006        Process->Win32Desktop = *(PHANDLE)ProcessInformation;
1007        Status = STATUS_SUCCESS;
1008        break;
1009      }
1010    ObDereferenceObject(Process);
1011    return(Status);
1012 }
1013
1014
1015 /**********************************************************************
1016  * NAME                                                 INTERNAL
1017  *      PiQuerySystemProcessInformation
1018  *
1019  * DESCRIPTION
1020  *      Compute the size of a process+thread snapshot as 
1021  *      expected by NtQuerySystemInformation.
1022  *
1023  * RETURN VALUE
1024  *      0 on error; otherwise the size, in bytes of the buffer
1025  *      required to write a full snapshot.
1026  *
1027  * NOTE
1028  *      We assume (sizeof (PVOID) == sizeof (ULONG)) holds.
1029  */
1030 NTSTATUS
1031 PiQuerySystemProcessInformation(PVOID Buffer,
1032                                 ULONG Size,
1033                                 PULONG ReqSize)
1034 {
1035    return STATUS_NOT_IMPLEMENTED;
1036
1037 #if 0
1038         KIRQL           OldIrql;
1039         PLIST_ENTRY     CurrentEntryP;
1040         PEPROCESS       CurrentP;
1041         PLIST_ENTRY     CurrentEntryT;
1042         PETHREAD        CurrentT;
1043         
1044         ULONG           RequiredSize = 0L;
1045         BOOLEAN         SizeOnly = FALSE;
1046
1047         ULONG           SpiSize = 0L;
1048         
1049         PSYSTEM_PROCESS_INFORMATION     pInfoP = (PSYSTEM_PROCESS_INFORMATION) SnapshotBuffer;
1050         PSYSTEM_PROCESS_INFORMATION     pInfoPLast = NULL;
1051         PSYSTEM_THREAD_INFO             pInfoT = NULL;
1052         
1053
1054    /* Lock the process list. */
1055    KeAcquireSpinLock(&PsProcessListLock,
1056                      &OldIrql);
1057
1058         /*
1059          * Scan the process list. Since the
1060          * list is circular, the guard is false
1061          * after the last process.
1062          */
1063         for (   CurrentEntryP = PsProcessListHead.Flink;
1064                 (CurrentEntryP != & PsProcessListHead);
1065                 CurrentEntryP = CurrentEntryP->Flink
1066                 )
1067         {
1068                 /*
1069                  * Compute how much space is
1070                  * occupied in the snapshot
1071                  * by adding this process info.
1072                  * (at least one thread).
1073                  */
1074                 SpiSizeCurrent = sizeof (SYSTEM_PROCESS_INFORMATION);
1075                 RequiredSize += SpiSizeCurrent;
1076                 /*
1077                  * Do not write process data in the
1078                  * buffer if it is too small.
1079                  */
1080                 if (TRUE == SizeOnly) continue;
1081                 /*
1082                  * Check if the buffer can contain
1083                  * the full snapshot.
1084                  */
1085                 if (Size < RequiredSize)
1086                 {
1087                         SizeOnly = TRUE;
1088                         continue;
1089                 }
1090                 /* 
1091                  * Get a reference to the 
1092                  * process descriptor we are
1093                  * handling.
1094                  */
1095                 CurrentP = CONTAINING_RECORD(
1096                                 CurrentEntryP,
1097                                 EPROCESS, 
1098                                 ProcessListEntry
1099                                 );
1100                 /*
1101                  * Write process data in the buffer.
1102                  */
1103                 RtlZeroMemory (pInfoP, sizeof (SYSTEM_PROCESS_INFORMATION));
1104                 /* PROCESS */
1105                 pInfoP->ThreadCount = 0L;
1106                 pInfoP->ProcessId = CurrentP->UniqueProcessId;
1107                 RtlInitUnicodeString (
1108                         & pInfoP->Name,
1109                         CurrentP->ImageFileName
1110                         );
1111                 /* THREAD */
1112                 for (   pInfoT = & CurrentP->ThreadSysInfo [0],
1113                         CurrentEntryT = CurrentP->ThreadListHead.Flink;
1114                         
1115                         (CurrentEntryT != & CurrentP->ThreadListHead);
1116                         
1117                         pInfoT = & CurrentP->ThreadSysInfo [pInfoP->ThreadCount],
1118                         CurrentEntryT = CurrentEntryT->Flink
1119                         )
1120                 {
1121                         /*
1122                          * Recalculate the size of the
1123                          * information block.
1124                          */
1125                         if (0 < pInfoP->ThreadCount)
1126                         {
1127                                 RequiredSize += sizeof (SYSTEM_THREAD_INFORMATION);
1128                         }
1129                         /*
1130                          * Do not write thread data in the
1131                          * buffer if it is too small.
1132                          */
1133                         if (TRUE == SizeOnly) continue;
1134                         /*
1135                          * Check if the buffer can contain
1136                          * the full snapshot.
1137                          */
1138                         if (Size < RequiredSize)
1139                         {
1140                                 SizeOnly = TRUE;
1141                                 continue;
1142                         }
1143                         /* 
1144                          * Get a reference to the 
1145                          * thread descriptor we are
1146                          * handling.
1147                          */
1148                         CurrentT = CONTAINING_RECORD(
1149                                         CurrentEntryT,
1150                                         KTHREAD, 
1151                                         Tcb.ThreadListEntry
1152                                         );
1153                         /*
1154                          * Write thread data.
1155                          */
1156                         RtlZeroMemory (
1157                                 pInfoT,
1158                                 sizeof (SYSTEM_THREAD_INFORMATION)
1159                                 );
1160                         pInfoT->KernelTime      = CurrentT-> ;  /* TIME */
1161                         pInfoT->UserTime        = CurrentT-> ;  /* TIME */
1162                         pInfoT->CreateTime      = CurrentT-> ;  /* TIME */
1163                         pInfoT->TickCount       = CurrentT-> ;  /* ULONG */
1164                         pInfoT->StartEIP        = CurrentT-> ;  /* ULONG */
1165                         pInfoT->ClientId        = CurrentT-> ;  /* CLIENT_ID */
1166                         pInfoT->ClientId        = CurrentT-> ;  /* CLIENT_ID */
1167                         pInfoT->DynamicPriority = CurrentT-> ;  /* ULONG */
1168                         pInfoT->BasePriority    = CurrentT-> ;  /* ULONG */
1169                         pInfoT->nSwitches       = CurrentT-> ;  /* ULONG */
1170                         pInfoT->State           = CurrentT-> ;  /* DWORD */
1171                         pInfoT->WaitReason      = CurrentT-> ;  /* KWAIT_REASON */
1172                         /*
1173                          * Count the number of threads 
1174                          * this process has.
1175                          */
1176                         ++ pInfoP->ThreadCount;
1177                 }
1178                 /*
1179                  * Save the size of information
1180                  * stored in the buffer for the
1181                  * current process.
1182                  */
1183                 pInfoP->RelativeOffset = SpiSize;
1184                 /*
1185                  * Save a reference to the last
1186                  * valid information block.
1187                  */
1188                 pInfoPLast = pInfoP;
1189                 /*
1190                  * Compute the offset of the 
1191                  * SYSTEM_PROCESS_INFORMATION
1192                  * descriptor in the snapshot 
1193                  * buffer for the next process.
1194                  */
1195                 (ULONG) pInfoP += SpiSize;
1196         }
1197         /*
1198          * Unlock the process list.
1199          */
1200         KeReleaseSpinLock (
1201                 & PsProcessListLock,
1202                 OldIrql
1203                 );
1204         /*
1205          * Return the proper error status code,
1206          * if the buffer was too small.
1207          */
1208         if (TRUE == SizeOnly)
1209         {
1210                 if (NULL != RequiredSize)
1211                 {
1212                         *pRequiredSize = RequiredSize;
1213                 }
1214                 return STATUS_INFO_LENGTH_MISMATCH;
1215         }
1216         /*
1217          * Mark the end of the snapshot.
1218          */
1219         pInfoP->RelativeOffset = 0L;
1220         /* OK */        
1221         return STATUS_SUCCESS;
1222 #endif
1223 }
1224
1225 LARGE_INTEGER STDCALL
1226 PsGetProcessExitTime(VOID)
1227 {
1228   LARGE_INTEGER Li;
1229   Li.QuadPart = PsGetCurrentProcess()->ExitTime.QuadPart;
1230   return Li;
1231 }
1232
1233 BOOLEAN STDCALL
1234 PsIsThreadTerminating(IN PETHREAD Thread)
1235 {
1236   return(Thread->DeadThread);
1237 }
1238
1239
1240 NTSTATUS STDCALL
1241 PsLookupProcessByProcessId(IN PVOID ProcessId,
1242                            OUT PEPROCESS *Process)
1243 {
1244   KIRQL oldIrql;
1245   PLIST_ENTRY current_entry;
1246   PEPROCESS current;
1247
1248   KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
1249
1250   current_entry = PsProcessListHead.Flink;
1251   while (current_entry != &PsProcessListHead)
1252     {
1253       current = CONTAINING_RECORD(current_entry,
1254                                   EPROCESS,
1255                                   ProcessListEntry);
1256       if (current->UniqueProcessId == (ULONG)ProcessId)
1257         {
1258           *Process = current;
1259           ObReferenceObject(current);
1260           KeReleaseSpinLock(&PsProcessListLock, oldIrql);
1261           return(STATUS_SUCCESS);
1262         }
1263       current_entry = current_entry->Flink;
1264     }
1265
1266   KeReleaseSpinLock(&PsProcessListLock, oldIrql);
1267
1268   return(STATUS_INVALID_PARAMETER);
1269 }
1270
1271
1272 NTSTATUS STDCALL
1273 PsSetCreateProcessNotifyRoutine(IN PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,
1274                                 IN BOOLEAN Remove)
1275 {
1276   if (PiProcessNotifyRoutineCount >= MAX_PROCESS_NOTIFY_ROUTINE_COUNT)
1277     return(STATUS_INSUFFICIENT_RESOURCES);
1278
1279   PiProcessNotifyRoutine[PiProcessNotifyRoutineCount] = NotifyRoutine;
1280   PiProcessNotifyRoutineCount++;
1281
1282   return(STATUS_SUCCESS);
1283 }
1284
1285 #endif /* LIBCAPTIVE */
1286
1287 /* EOF */