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