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 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((LONG *)&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);
303
304    ObDereferenceObject(Process->Token);
305    ObDeleteHandleTable(Process);
306
307    (VOID)MmReleaseMmInfo(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 IoGetCurrentProcess(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 NTSTATUS STDCALL
385 PsCreateSystemProcess(PHANDLE ProcessHandle,
386                       ACCESS_MASK DesiredAccess,
387                       POBJECT_ATTRIBUTES ObjectAttributes)
388 {
389    return NtCreateProcess(ProcessHandle,
390                           DesiredAccess,
391                           ObjectAttributes,
392                           SystemProcessHandle,
393                           FALSE,
394                           NULL,
395                           NULL,
396                           NULL);
397 }
398
399 NTSTATUS STDCALL
400 NtCreateProcess(OUT PHANDLE ProcessHandle,
401                 IN ACCESS_MASK DesiredAccess,
402                 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
403                 IN HANDLE ParentProcessHandle,
404                 IN BOOLEAN InheritObjectTable,
405                 IN HANDLE SectionHandle OPTIONAL,
406                 IN HANDLE DebugPortHandle OPTIONAL,
407                 IN HANDLE ExceptionPortHandle OPTIONAL)
408 /*
409  * FUNCTION: Creates a process.
410  * ARGUMENTS:
411  *        ProcessHandle (OUT) = Caller supplied storage for the resulting 
412  *                              handle
413  *        DesiredAccess = Specifies the allowed or desired access to the 
414  *                        process can be a combination of 
415  *                        STANDARD_RIGHTS_REQUIRED| ..  
416  *        ObjectAttribute = Initialized attributes for the object, contains 
417  *                          the rootdirectory and the filename
418  *        ParentProcess = Handle to the parent process.
419  *        InheritObjectTable = Specifies to inherit the objects of the parent 
420  *                             process if true.
421  *        SectionHandle = Handle to a section object to back the image file
422  *        DebugPort = Handle to a DebugPort if NULL the system default debug 
423  *                    port will be used.
424  *        ExceptionPort = Handle to a exception port. 
425  * REMARKS:
426  *        This function maps to the win32 CreateProcess. 
427  * RETURNS: Status
428  */
429 {
430    PEPROCESS Process;
431    PEPROCESS ParentProcess;
432    PKPROCESS KProcess;
433    NTSTATUS Status;
434    KIRQL oldIrql;
435    PVOID LdrStartupAddr;
436    PVOID ImageBase;
437    PVOID Peb;
438    PEPORT DebugPort;
439    PEPORT ExceptionPort;
440    PVOID BaseAddress;
441    PMEMORY_AREA MemoryArea;
442    ULONG i;
443    
444    DPRINT("NtCreateProcess(ObjectAttributes %x)\n",ObjectAttributes);
445
446    Status = ObReferenceObjectByHandle(ParentProcessHandle,
447                                       PROCESS_CREATE_PROCESS,
448                                       PsProcessType,
449                                       ExGetPreviousMode(),
450                                       (PVOID*)&ParentProcess,
451                                       NULL);
452    if (!NT_SUCCESS(Status))
453      {
454         DPRINT("NtCreateProcess() = %x\n",Status);
455         return(Status);
456      }
457
458    Status = ObCreateObject(ProcessHandle,
459                            DesiredAccess,
460                            ObjectAttributes,
461                            PsProcessType,
462                            (PVOID*)&Process);
463    if (!NT_SUCCESS(Status))
464      {
465         ObDereferenceObject(ParentProcess);
466         DPRINT("ObCreateObject() = %x\n",Status);
467         return(Status);
468      }
469
470    KeInitializeDispatcherHeader(&Process->Pcb.DispatcherHeader,
471                                 InternalProcessType,
472                                 sizeof(EPROCESS),
473                                 FALSE);
474    KProcess = &Process->Pcb;
475    /* Inherit parent process's affinity. */
476    KProcess->Affinity = ParentProcess->Pcb.Affinity;
477    KProcess->BasePriority = PROCESS_PRIO_NORMAL;
478    MmInitializeAddressSpace(Process,
479                             &Process->AddressSpace);
480    Process->UniqueProcessId = InterlockedIncrement((LONG *)&PiNextProcessUniqueId);
481    Process->InheritedFromUniqueProcessId = 
482      (HANDLE)ParentProcess->UniqueProcessId;
483    ObCreateHandleTable(ParentProcess,
484                        InheritObjectTable,
485                        Process);
486    MmCopyMmInfo(ParentProcess, Process);
487    if (ParentProcess->Win32WindowStation != (HANDLE)0)
488      {
489        /* Always duplicate the process window station. */
490        Process->Win32WindowStation = 0;
491        Status = ObDuplicateObject(ParentProcess,
492                                   Process,
493                                   ParentProcess->Win32WindowStation,
494                                   &Process->Win32WindowStation,
495                                   0,
496                                   FALSE,
497                                   DUPLICATE_SAME_ACCESS);
498        if (!NT_SUCCESS(Status))
499          {
500            KeBugCheck(0);
501          }
502      }
503    else
504      {
505        Process->Win32WindowStation = (HANDLE)0;
506      }
507    if (ParentProcess->Win32Desktop != (HANDLE)0)
508      {
509        /* Always duplicate the process window station. */
510        Process->Win32Desktop = 0;
511        Status = ObDuplicateObject(ParentProcess,
512                                   Process,
513                                   ParentProcess->Win32Desktop,
514                                   &Process->Win32Desktop,
515                                   0,
516                                   FALSE,
517                                   DUPLICATE_SAME_ACCESS);
518        if (!NT_SUCCESS(Status))
519          {
520            KeBugCheck(0);
521          }
522      }
523    else
524      {
525        Process->Win32Desktop = (HANDLE)0;
526      }
527
528    KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
529    for (i = 0; i < PiProcessNotifyRoutineCount; i++)
530     {
531       PiProcessNotifyRoutine[i](Process->InheritedFromUniqueProcessId,
532                                 (HANDLE)Process->UniqueProcessId,
533                                 TRUE);
534     }
535    InsertHeadList(&PsProcessListHead, &Process->ProcessListEntry);
536    InitializeListHead(&Process->ThreadListHead);
537    KeReleaseSpinLock(&PsProcessListLock, oldIrql);
538    
539    Process->Pcb.State = PROCESS_STATE_ACTIVE;
540    
541    /*
542     * Add the debug port
543     */
544    if (DebugPortHandle != NULL)
545      {
546         Status = ObReferenceObjectByHandle(DebugPortHandle,
547                                            PORT_ALL_ACCESS,
548                                            ExPortType,
549                                            UserMode,
550                                            (PVOID*)&DebugPort,
551                                            NULL);   
552         if (!NT_SUCCESS(Status))
553           {
554              ObDereferenceObject(Process);
555              ObDereferenceObject(ParentProcess);
556              ZwClose(*ProcessHandle);
557              *ProcessHandle = NULL;
558              return(Status);
559           }
560         Process->DebugPort = DebugPort;
561      }
562         
563    /*
564     * Add the exception port
565     */
566    if (ExceptionPortHandle != NULL)
567      {
568         Status = ObReferenceObjectByHandle(ExceptionPortHandle,
569                                            PORT_ALL_ACCESS,
570                                            ExPortType,
571                                            UserMode,
572                                            (PVOID*)&ExceptionPort,
573                                            NULL);   
574         if (!NT_SUCCESS(Status))
575           {
576              ObDereferenceObject(Process);
577              ObDereferenceObject(ParentProcess);
578              ZwClose(*ProcessHandle);
579              *ProcessHandle = NULL;
580              return(Status);
581           }
582         Process->ExceptionPort = ExceptionPort;
583      }
584    
585    /*
586     * Now we have created the process proper
587     */
588    
589    /*
590     * Create the shared data page
591     */
592    MmLockAddressSpace(&Process->AddressSpace);
593    BaseAddress = (PVOID)USER_SHARED_DATA;
594    Status = MmCreateMemoryArea(Process,
595                                &Process->AddressSpace,
596                                MEMORY_AREA_SHARED_DATA,
597                                &BaseAddress,
598                                PAGE_SIZE,
599                                PAGE_READONLY,
600                                &MemoryArea,
601                                FALSE);
602    MmUnlockAddressSpace(&Process->AddressSpace);
603    if (!NT_SUCCESS(Status))
604      {
605         DPRINT1("Failed to create shared data page\n");
606         KeBugCheck(0);
607      }
608    
609    /*
610     * Map ntdll
611     */
612    Status = LdrpMapSystemDll(*ProcessHandle,
613                              &LdrStartupAddr);
614    if (!NT_SUCCESS(Status))
615      {
616         DbgPrint("LdrpMapSystemDll failed (Status %x)\n", Status);
617         ObDereferenceObject(Process);
618         ObDereferenceObject(ParentProcess);
619         return(Status);
620      }
621    
622    /*
623     * Map the process image
624     */
625    if (SectionHandle != NULL)
626      {
627         DPRINT("Mapping process image\n");
628         Status = LdrpMapImage(*ProcessHandle,
629                               SectionHandle,
630                               &ImageBase);
631         if (!NT_SUCCESS(Status))
632           {
633              DbgPrint("LdrpMapImage failed (Status %x)\n", Status);
634              ObDereferenceObject(Process);
635              ObDereferenceObject(ParentProcess);
636              return(Status);
637           }
638      }
639    else
640      {
641         ImageBase = NULL;
642      }
643    
644   /*
645    * Duplicate the token
646    */
647   Status = SepInitializeNewProcess(Process, ParentProcess);
648   if (!NT_SUCCESS(Status))
649     {
650        DbgPrint("SepInitializeNewProcess failed (Status %x)\n", Status);
651        ObDereferenceObject(Process);
652        ObDereferenceObject(ParentProcess);
653        return(Status);
654     }
655
656    /*
657     * 
658     */
659    DPRINT("Creating PEB\n");
660    Status = PsCreatePeb(*ProcessHandle,
661                         ImageBase,
662                         &Peb);
663    if (!NT_SUCCESS(Status))
664      {
665         DbgPrint("NtCreateProcess() Peb creation failed: Status %x\n",Status);
666         ObDereferenceObject(Process);
667         ObDereferenceObject(ParentProcess);
668         ZwClose(*ProcessHandle);
669         *ProcessHandle = NULL;
670         return(Status);
671      }
672    Process->Peb = Peb;
673    
674    /*
675     * Maybe send a message to the creator process's debugger
676     */
677 #if 0
678    if (ParentProcess->DebugPort != NULL)
679      {
680         LPC_DBG_MESSAGE Message;
681         HANDLE FileHandle;
682         
683         ObCreateHandle(NULL, // Debugger Process
684                        NULL, // SectionHandle
685                        FILE_ALL_ACCESS,
686                        FALSE,
687                        &FileHandle);
688         
689         Message.Header.MessageSize = sizeof(LPC_DBG_MESSAGE);
690         Message.Header.DataSize = sizeof(LPC_DBG_MESSAGE) -
691           sizeof(LPC_MESSAGE);
692         Message.Type = DBG_EVENT_CREATE_PROCESS;
693         Message.Data.CreateProcess.FileHandle = FileHandle;
694         Message.Data.CreateProcess.Base = ImageBase;
695         Message.Data.CreateProcess.EntryPoint = NULL; //
696         
697         Status = LpcSendDebugMessagePort(ParentProcess->DebugPort,
698                                          &Message);
699      }
700 #endif
701    
702    ObDereferenceObject(Process);
703    ObDereferenceObject(ParentProcess);
704    return(STATUS_SUCCESS);
705 }
706
707
708 NTSTATUS STDCALL
709 NtOpenProcess(OUT PHANDLE           ProcessHandle,
710               IN  ACCESS_MASK       DesiredAccess,
711               IN  POBJECT_ATTRIBUTES  ObjectAttributes,
712               IN  PCLIENT_ID        ClientId)
713 {
714    DPRINT("NtOpenProcess(ProcessHandle %x, DesiredAccess %x, "
715           "ObjectAttributes %x, ClientId %x { UniP %d, UniT %d })\n",
716           ProcessHandle, DesiredAccess, ObjectAttributes, ClientId,
717           ClientId->UniqueProcess, ClientId->UniqueThread);
718           
719    
720    /*
721     * Not sure of the exact semantics 
722     */
723    if (ObjectAttributes != NULL && ObjectAttributes->ObjectName != NULL &&
724        ObjectAttributes->ObjectName->Buffer != NULL)
725      {
726         NTSTATUS Status;
727         PEPROCESS Process;
728                 
729         Status = ObReferenceObjectByName(ObjectAttributes->ObjectName,
730                                          ObjectAttributes->Attributes,
731                                          NULL,
732                                          DesiredAccess,
733                                          PsProcessType,
734                                          UserMode,
735                                          NULL,
736                                          (PVOID*)&Process);
737         if (Status != STATUS_SUCCESS)
738           {
739              return(Status);
740           }
741         
742         Status = ObCreateHandle(PsGetCurrentProcess(),
743                                 Process,
744                                 DesiredAccess,
745                                 FALSE,
746                                 ProcessHandle);
747         ObDereferenceObject(Process);
748    
749         return(Status);
750      }
751    else
752      {
753         KIRQL oldIrql;
754         PLIST_ENTRY current_entry;
755         PEPROCESS current;
756         NTSTATUS Status;
757         
758         KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
759         current_entry = PsProcessListHead.Flink;
760         while (current_entry != &PsProcessListHead)
761           {
762              current = CONTAINING_RECORD(current_entry, EPROCESS, 
763                                          ProcessListEntry);
764              if (current->UniqueProcessId == (ULONG)ClientId->UniqueProcess)
765                {
766                   ObReferenceObjectByPointer(current,
767                                              DesiredAccess,
768                                              PsProcessType,
769                                              UserMode);
770                   KeReleaseSpinLock(&PsProcessListLock, oldIrql);
771                   Status = ObCreateHandle(PsGetCurrentProcess(),
772                                           current,
773                                           DesiredAccess,
774                                           FALSE,
775                                           ProcessHandle);
776                   ObDereferenceObject(current);
777                   DPRINT("*ProcessHandle %x\n", ProcessHandle);
778                   DPRINT("NtOpenProcess() = %x\n", Status);
779                   return(Status);
780                }
781              current_entry = current_entry->Flink;
782           }
783         KeReleaseSpinLock(&PsProcessListLock, oldIrql);
784         DPRINT("NtOpenProcess() = STATUS_UNSUCCESSFUL\n");
785         return(STATUS_UNSUCCESSFUL);
786      }
787    return(STATUS_UNSUCCESSFUL);
788 }
789
790
791 NTSTATUS STDCALL
792 NtQueryInformationProcess(IN  HANDLE ProcessHandle,
793                           IN  CINT ProcessInformationClass,
794                           OUT PVOID ProcessInformation,
795                           IN  ULONG ProcessInformationLength,
796                           OUT PULONG ReturnLength)
797 {
798    PEPROCESS Process;
799    NTSTATUS Status;
800    PPROCESS_BASIC_INFORMATION ProcessBasicInformationP;
801    
802    Status = ObReferenceObjectByHandle(ProcessHandle,
803                                       PROCESS_SET_INFORMATION,
804                                       PsProcessType,
805                                       UserMode,
806                                       (PVOID*)&Process,
807                                       NULL);
808    if (Status != STATUS_SUCCESS)
809      {
810         return(Status);
811      }
812    
813    switch (ProcessInformationClass)
814      {
815       case ProcessBasicInformation:
816         ProcessBasicInformationP = (PPROCESS_BASIC_INFORMATION)
817           ProcessInformation;
818         ProcessBasicInformationP->ExitStatus = Process->ExitStatus;
819         ProcessBasicInformationP->PebBaseAddress = Process->Peb;
820         ProcessBasicInformationP->AffinityMask = Process->Pcb.Affinity;
821         ProcessBasicInformationP->UniqueProcessId =
822           Process->UniqueProcessId;
823         ProcessBasicInformationP->InheritedFromUniqueProcessId =
824           (ULONG)Process->InheritedFromUniqueProcessId;
825         Status = STATUS_SUCCESS;
826         break;
827         
828       case ProcessQuotaLimits:
829       case ProcessIoCounters:
830       case ProcessVmCounters:
831       case ProcessTimes:
832       case ProcessDebugPort:
833       case ProcessLdtInformation:
834         Status = STATUS_NOT_IMPLEMENTED;
835         break;
836         
837       case ProcessDefaultHardErrorMode:
838         *((PULONG)ProcessInformation) = Process->DefaultHardErrorProcessing;
839         break;
840         
841       case ProcessWorkingSetWatch:
842         Status = STATUS_NOT_IMPLEMENTED;
843         break;
844
845       case ProcessWx86Information:
846       case ProcessHandleCount:
847       case ProcessPriorityBoost:
848       case ProcessDeviceMap:
849       case ProcessSessionInformation:
850       case ProcessWow64Information:
851         Status = STATUS_NOT_IMPLEMENTED;
852         break;
853         
854       case ProcessBasePriority:
855       case ProcessRaisePriority:
856       case ProcessExceptionPort:
857       case ProcessAccessToken:
858       case ProcessLdtSize:
859       case ProcessIoPortHandlers:
860       case ProcessUserModeIOPL:
861       case ProcessEnableAlignmentFaultFixup:
862       case ProcessPriorityClass:
863       case ProcessAffinityMask:
864       case ProcessForegroundInformation:
865       default:
866         Status = STATUS_INVALID_INFO_CLASS;
867      }
868    ObDereferenceObject(Process);
869    return(Status);
870 }
871
872 NTSTATUS
873 PspAssignPrimaryToken(PEPROCESS Process,
874                       HANDLE TokenHandle)
875 {
876    PACCESS_TOKEN Token;
877    PACCESS_TOKEN OldToken;
878    NTSTATUS Status;
879    
880    Status = ObReferenceObjectByHandle(TokenHandle,
881                                       0,
882                                       SepTokenObjectType,
883                                       UserMode,
884                                       (PVOID*)&Token,
885                                       NULL);
886    if (!NT_SUCCESS(Status))
887      {
888         return(Status);
889      }
890    Status = SeExchangePrimaryToken(Process, Token, &OldToken);
891    if (NT_SUCCESS(Status))
892      {
893         ObDereferenceObject(OldToken);
894      }
895    ObDereferenceObject(Token);
896    return(Status);
897 }
898
899 NTSTATUS STDCALL
900 NtSetInformationProcess(IN HANDLE ProcessHandle,
901                         IN CINT ProcessInformationClass,
902                         IN PVOID ProcessInformation,
903                         IN ULONG ProcessInformationLength)
904 {
905    PEPROCESS Process;
906    NTSTATUS Status;
907    PHANDLE ProcessAccessTokenP;
908    
909    Status = ObReferenceObjectByHandle(ProcessHandle,
910                                       PROCESS_SET_INFORMATION,
911                                       PsProcessType,
912                                       UserMode,
913                                       (PVOID*)&Process,
914                                       NULL);
915    if (!NT_SUCCESS(Status))
916      {
917         return(Status);
918      }
919
920    switch (ProcessInformationClass)
921      {
922       case ProcessQuotaLimits:
923       case ProcessBasePriority:
924       case ProcessRaisePriority:
925       case ProcessDebugPort:
926       case ProcessExceptionPort:
927         Status = STATUS_NOT_IMPLEMENTED;
928         break;
929
930       case ProcessAccessToken:
931         ProcessAccessTokenP = (PHANDLE)ProcessInformation;
932         Status = PspAssignPrimaryToken(Process, *ProcessAccessTokenP);
933         break;
934         
935       case ProcessImageFileName:
936         memcpy(Process->ImageFileName, ProcessInformation, 8);
937         Status = STATUS_SUCCESS;
938         break;
939         
940       case ProcessLdtInformation:
941       case ProcessLdtSize:
942       case ProcessDefaultHardErrorMode:
943       case ProcessIoPortHandlers:
944       case ProcessWorkingSetWatch:
945       case ProcessUserModeIOPL:
946       case ProcessEnableAlignmentFaultFixup:
947       case ProcessPriorityClass:
948       case ProcessAffinityMask:
949         Status = STATUS_NOT_IMPLEMENTED;
950         break;
951
952       case ProcessBasicInformation:
953       case ProcessIoCounters:
954       case ProcessVmCounters:
955       case ProcessTimes:
956       case ProcessPooledUsageAndLimits:
957       case ProcessWx86Information:
958       case ProcessHandleCount:
959       case ProcessWow64Information:
960       default:
961         Status = STATUS_INVALID_INFO_CLASS;
962
963      case ProcessDesktop:
964        Process->Win32Desktop = *(PHANDLE)ProcessInformation;
965        Status = STATUS_SUCCESS;
966        break;
967      }
968    ObDereferenceObject(Process);
969    return(Status);
970 }
971
972
973 /**********************************************************************
974  * NAME                                                 INTERNAL
975  *      PiQuerySystemProcessInformation
976  *
977  * DESCRIPTION
978  *      Compute the size of a process+thread snapshot as 
979  *      expected by NtQuerySystemInformation.
980  *
981  * RETURN VALUE
982  *      0 on error; otherwise the size, in bytes of the buffer
983  *      required to write a full snapshot.
984  *
985  * NOTE
986  *      We assume (sizeof (PVOID) == sizeof (ULONG)) holds.
987  */
988 NTSTATUS
989 PiQuerySystemProcessInformation(PVOID Buffer,
990                                 ULONG Size,
991                                 PULONG ReqSize)
992 {
993    return STATUS_NOT_IMPLEMENTED;
994
995 #if 0
996         KIRQL           OldIrql;
997         PLIST_ENTRY     CurrentEntryP;
998         PEPROCESS       CurrentP;
999         PLIST_ENTRY     CurrentEntryT;
1000         PETHREAD        CurrentT;
1001         
1002         ULONG           RequiredSize = 0L;
1003         BOOLEAN         SizeOnly = FALSE;
1004
1005         ULONG           SpiSize = 0L;
1006         
1007         PSYSTEM_PROCESS_INFORMATION     pInfoP = (PSYSTEM_PROCESS_INFORMATION) SnapshotBuffer;
1008         PSYSTEM_PROCESS_INFORMATION     pInfoPLast = NULL;
1009         PSYSTEM_THREAD_INFO             pInfoT = NULL;
1010         
1011
1012    /* Lock the process list. */
1013    KeAcquireSpinLock(&PsProcessListLock,
1014                      &OldIrql);
1015
1016         /*
1017          * Scan the process list. Since the
1018          * list is circular, the guard is false
1019          * after the last process.
1020          */
1021         for (   CurrentEntryP = PsProcessListHead.Flink;
1022                 (CurrentEntryP != & PsProcessListHead);
1023                 CurrentEntryP = CurrentEntryP->Flink
1024                 )
1025         {
1026                 /*
1027                  * Compute how much space is
1028                  * occupied in the snapshot
1029                  * by adding this process info.
1030                  * (at least one thread).
1031                  */
1032                 SpiSizeCurrent = sizeof (SYSTEM_PROCESS_INFORMATION);
1033                 RequiredSize += SpiSizeCurrent;
1034                 /*
1035                  * Do not write process data in the
1036                  * buffer if it is too small.
1037                  */
1038                 if (TRUE == SizeOnly) continue;
1039                 /*
1040                  * Check if the buffer can contain
1041                  * the full snapshot.
1042                  */
1043                 if (Size < RequiredSize)
1044                 {
1045                         SizeOnly = TRUE;
1046                         continue;
1047                 }
1048                 /* 
1049                  * Get a reference to the 
1050                  * process descriptor we are
1051                  * handling.
1052                  */
1053                 CurrentP = CONTAINING_RECORD(
1054                                 CurrentEntryP,
1055                                 EPROCESS, 
1056                                 ProcessListEntry
1057                                 );
1058                 /*
1059                  * Write process data in the buffer.
1060                  */
1061                 RtlZeroMemory (pInfoP, sizeof (SYSTEM_PROCESS_INFORMATION));
1062                 /* PROCESS */
1063                 pInfoP->ThreadCount = 0L;
1064                 pInfoP->ProcessId = CurrentP->UniqueProcessId;
1065                 RtlInitUnicodeString (
1066                         & pInfoP->Name,
1067                         CurrentP->ImageFileName
1068                         );
1069                 /* THREAD */
1070                 for (   pInfoT = & CurrentP->ThreadSysInfo [0],
1071                         CurrentEntryT = CurrentP->ThreadListHead.Flink;
1072                         
1073                         (CurrentEntryT != & CurrentP->ThreadListHead);
1074                         
1075                         pInfoT = & CurrentP->ThreadSysInfo [pInfoP->ThreadCount],
1076                         CurrentEntryT = CurrentEntryT->Flink
1077                         )
1078                 {
1079                         /*
1080                          * Recalculate the size of the
1081                          * information block.
1082                          */
1083                         if (0 < pInfoP->ThreadCount)
1084                         {
1085                                 RequiredSize += sizeof (SYSTEM_THREAD_INFORMATION);
1086                         }
1087                         /*
1088                          * Do not write thread data in the
1089                          * buffer if it is too small.
1090                          */
1091                         if (TRUE == SizeOnly) continue;
1092                         /*
1093                          * Check if the buffer can contain
1094                          * the full snapshot.
1095                          */
1096                         if (Size < RequiredSize)
1097                         {
1098                                 SizeOnly = TRUE;
1099                                 continue;
1100                         }
1101                         /* 
1102                          * Get a reference to the 
1103                          * thread descriptor we are
1104                          * handling.
1105                          */
1106                         CurrentT = CONTAINING_RECORD(
1107                                         CurrentEntryT,
1108                                         KTHREAD, 
1109                                         Tcb.ThreadListEntry
1110                                         );
1111                         /*
1112                          * Write thread data.
1113                          */
1114                         RtlZeroMemory (
1115                                 pInfoT,
1116                                 sizeof (SYSTEM_THREAD_INFORMATION)
1117                                 );
1118                         pInfoT->KernelTime      = CurrentT-> ;  /* TIME */
1119                         pInfoT->UserTime        = CurrentT-> ;  /* TIME */
1120                         pInfoT->CreateTime      = CurrentT-> ;  /* TIME */
1121                         pInfoT->TickCount       = CurrentT-> ;  /* ULONG */
1122                         pInfoT->StartEIP        = CurrentT-> ;  /* ULONG */
1123                         pInfoT->ClientId        = CurrentT-> ;  /* CLIENT_ID */
1124                         pInfoT->ClientId        = CurrentT-> ;  /* CLIENT_ID */
1125                         pInfoT->DynamicPriority = CurrentT-> ;  /* ULONG */
1126                         pInfoT->BasePriority    = CurrentT-> ;  /* ULONG */
1127                         pInfoT->nSwitches       = CurrentT-> ;  /* ULONG */
1128                         pInfoT->State           = CurrentT-> ;  /* DWORD */
1129                         pInfoT->WaitReason      = CurrentT-> ;  /* KWAIT_REASON */
1130                         /*
1131                          * Count the number of threads 
1132                          * this process has.
1133                          */
1134                         ++ pInfoP->ThreadCount;
1135                 }
1136                 /*
1137                  * Save the size of information
1138                  * stored in the buffer for the
1139                  * current process.
1140                  */
1141                 pInfoP->RelativeOffset = SpiSize;
1142                 /*
1143                  * Save a reference to the last
1144                  * valid information block.
1145                  */
1146                 pInfoPLast = pInfoP;
1147                 /*
1148                  * Compute the offset of the 
1149                  * SYSTEM_PROCESS_INFORMATION
1150                  * descriptor in the snapshot 
1151                  * buffer for the next process.
1152                  */
1153                 (ULONG) pInfoP += SpiSize;
1154         }
1155         /*
1156          * Unlock the process list.
1157          */
1158         KeReleaseSpinLock (
1159                 & PsProcessListLock,
1160                 OldIrql
1161                 );
1162         /*
1163          * Return the proper error status code,
1164          * if the buffer was too small.
1165          */
1166         if (TRUE == SizeOnly)
1167         {
1168                 if (NULL != RequiredSize)
1169                 {
1170                         *pRequiredSize = RequiredSize;
1171                 }
1172                 return STATUS_INFO_LENGTH_MISMATCH;
1173         }
1174         /*
1175          * Mark the end of the snapshot.
1176          */
1177         pInfoP->RelativeOffset = 0L;
1178         /* OK */        
1179         return STATUS_SUCCESS;
1180 #endif
1181 }
1182
1183 LARGE_INTEGER STDCALL
1184 PsGetProcessExitTime(VOID)
1185 {
1186   LARGE_INTEGER Li;
1187   Li.QuadPart = PsGetCurrentProcess()->ExitTime.QuadPart;
1188   return Li;
1189 }
1190
1191 BOOLEAN STDCALL
1192 PsIsThreadTerminating(IN PETHREAD Thread)
1193 {
1194   return(Thread->DeadThread);
1195 }
1196
1197
1198 NTSTATUS STDCALL
1199 PsLookupProcessByProcessId(IN PVOID ProcessId,
1200                            OUT PEPROCESS *Process)
1201 {
1202   KIRQL oldIrql;
1203   PLIST_ENTRY current_entry;
1204   PEPROCESS current;
1205
1206   KeAcquireSpinLock(&PsProcessListLock, &oldIrql);
1207
1208   current_entry = PsProcessListHead.Flink;
1209   while (current_entry != &PsProcessListHead)
1210     {
1211       current = CONTAINING_RECORD(current_entry,
1212                                   EPROCESS,
1213                                   ProcessListEntry);
1214       if (current->UniqueProcessId == (ULONG)ProcessId)
1215         {
1216           *Process = current;
1217           ObReferenceObject(current);
1218           KeReleaseSpinLock(&PsProcessListLock, oldIrql);
1219           return(STATUS_SUCCESS);
1220         }
1221       current_entry = current_entry->Flink;
1222     }
1223
1224   KeReleaseSpinLock(&PsProcessListLock, oldIrql);
1225
1226   return(STATUS_INVALID_PARAMETER);
1227 }
1228
1229
1230 NTSTATUS STDCALL
1231 PsSetCreateProcessNotifyRoutine(IN PCREATE_PROCESS_NOTIFY_ROUTINE NotifyRoutine,
1232                                 IN BOOLEAN Remove)
1233 {
1234   if (PiProcessNotifyRoutineCount >= MAX_PROCESS_NOTIFY_ROUTINE_COUNT)
1235     return(STATUS_INSUFFICIENT_RESOURCES);
1236
1237   PiProcessNotifyRoutine[PiProcessNotifyRoutineCount] = NotifyRoutine;
1238   PiProcessNotifyRoutineCount++;
1239
1240   return(STATUS_SUCCESS);
1241 }
1242
1243 /* EOF */