Do always dereference the section object if it was created (in PspCreateProcess).
[reactos.git] / reactos / ntoskrnl / ps / process.c
index e12a8e8..df3993d 100644 (file)
 PEPROCESS EXPORTED PsInitialSystemProcess = NULL;
 PEPROCESS PsIdleProcess = NULL;
 POBJECT_TYPE EXPORTED PsProcessType = NULL;
+extern PHANDLE_TABLE PspCidTable;
+
+EPROCESS_QUOTA_BLOCK PspDefaultQuotaBlock;
 
 LIST_ENTRY PsActiveProcessHead;
 FAST_MUTEX PspActiveProcessMutex;
 LARGE_INTEGER ShortPsLockDelay, PsLockTimeout;
-                             
+
 /* INTERNAL FUNCTIONS *****************************************************************/
 
 NTSTATUS
+NTAPI
 PsLockProcess(PEPROCESS Process, BOOLEAN Timeout)
 {
   ULONG Attempts = 0;
@@ -34,11 +38,11 @@ PsLockProcess(PEPROCESS Process, BOOLEAN Timeout)
   NTSTATUS Status = STATUS_UNSUCCESSFUL;
   PLARGE_INTEGER Delay = (Timeout ? &PsLockTimeout : NULL);
   PKTHREAD CallingThread = KeGetCurrentThread();
-  
+
   PAGED_CODE();
-  
+
   KeEnterCriticalRegion();
-  
+
   for(;;)
   {
     PrevLockOwner = (PKTHREAD)InterlockedCompareExchangePointer(
@@ -80,23 +84,24 @@ PsLockProcess(PEPROCESS Process, BOOLEAN Timeout)
       }
     }
   }
-  
+
   return Status;
 }
 
 VOID
+NTAPI
 PsUnlockProcess(PEPROCESS Process)
 {
   PAGED_CODE();
-  
+
   ASSERT(Process->LockOwner == KeGetCurrentThread());
-  
+
   if(InterlockedDecrementUL(&Process->LockCount) == 0)
   {
     InterlockedExchangePointer(&Process->LockOwner, NULL);
     KeSetEvent(&Process->LockEvent, IO_NO_INCREMENT, FALSE);
   }
-  
+
   KeLeaveCriticalRegion();
 }
 
@@ -106,7 +111,7 @@ PsGetNextProcess(PEPROCESS OldProcess)
 {
     PEPROCESS NextProcess;
     NTSTATUS Status;
-   
+
     /* Check if we have a previous process */
     if (OldProcess == NULL)
     {
@@ -114,33 +119,33 @@ PsGetNextProcess(PEPROCESS OldProcess)
         Status = ObReferenceObjectByPointer(PsIdleProcess,
                                             PROCESS_ALL_ACCESS,
                                             PsProcessType,
-                                            KernelMode);   
+                                            KernelMode);
         if (!NT_SUCCESS(Status))
         {
             DPRINT1("PsGetNextProcess(): ObReferenceObjectByPointer failed for PsIdleProcess\n");
             KEBUGCHECK(0);
         }
-        
+
         return PsIdleProcess;
     }
-   
+
     /* Acquire the Active Process Lock */
     ExAcquireFastMutex(&PspActiveProcessMutex);
-    
+
     /* Start at the previous process */
     NextProcess = OldProcess;
-    
+
     /* Loop until we fail */
     while (1)
     {
         /* Get the Process Link */
         PLIST_ENTRY Flink = (NextProcess == PsIdleProcess ? PsActiveProcessHead.Flink :
-                             NextProcess->ProcessListEntry.Flink);
-        
+                             NextProcess->ActiveProcessLinks.Flink);
+
         /* Move to the next Process if we're not back at the beginning */
         if (Flink != &PsActiveProcessHead)
         {
-            NextProcess = CONTAINING_RECORD(Flink, EPROCESS, ProcessListEntry);
+            NextProcess = CONTAINING_RECORD(Flink, EPROCESS, ActiveProcessLinks);
         }
         else
         {
@@ -154,13 +159,13 @@ PsGetNextProcess(PEPROCESS OldProcess)
                                             PsProcessType,
                                             KernelMode);
 
-        /* Exit the loop if the reference worked, keep going if there's an error */               
+        /* Exit the loop if the reference worked, keep going if there's an error */
         if (NT_SUCCESS(Status)) break;
     }
-    
+
     /* Release the lock */
     ExReleaseFastMutex(&PspActiveProcessMutex);
-    
+
     /* Reference the Process we had referenced earlier */
     ObDereferenceObject(OldProcess);
     return(NextProcess);
@@ -178,8 +183,8 @@ PspCreateProcess(OUT PHANDLE ProcessHandle,
                  IN HANDLE ExceptionPort  OPTIONAL)
 {
     HANDLE hProcess;
-    PEPROCESS Process;
-    PEPROCESS pParentProcess;  
+    PEPROCESS Process = NULL;
+    PEPROCESS pParentProcess = NULL;
     PEPORT pDebugPort = NULL;
     PEPORT pExceptionPort = NULL;
     PSECTION_OBJECT SectionObject = NULL;
@@ -187,12 +192,14 @@ PspCreateProcess(OUT PHANDLE ProcessHandle,
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     PHYSICAL_ADDRESS DirectoryTableBase;
     KAFFINITY Affinity;
+    HANDLE_TABLE_ENTRY CidEntry;
     DirectoryTableBase.QuadPart = (ULONGLONG)0;
+    BOOLEAN ProcessCreated = FALSE;
 
     DPRINT("PspCreateProcess(ObjectAttributes %x)\n", ObjectAttributes);
-   
+
     /* Reference the Parent if there is one */
-    if(ParentProcess != NULL) 
+    if(ParentProcess != NULL)
     {
         Status = ObReferenceObjectByHandle(ParentProcess,
                                            PROCESS_CREATE_PROCESS,
@@ -200,41 +207,48 @@ PspCreateProcess(OUT PHANDLE ProcessHandle,
                                            PreviousMode,
                                            (PVOID*)&pParentProcess,
                                            NULL);
-        
-        if (!NT_SUCCESS(Status)) 
+
+        if (!NT_SUCCESS(Status))
         {
             DPRINT1("Failed to reference the parent process: Status: 0x%x\n", Status);
-            return(Status);
+            goto Cleanup;
         }
-        
+
         /* Inherit Parent process's Affinity. */
-        Affinity = pParentProcess->Pcb.Affinity;  
-        
-    } 
-    else 
+        Affinity = pParentProcess->Pcb.Affinity;
+
+    }
+    else
     {
         pParentProcess = NULL;
+#ifdef CONFIG_SMP        
+   /* FIXME:
+    *   Only the boot cpu is initialized in the early boot phase. 
+    */
+        Affinity = 0xffffffff;
+#else
         Affinity = KeActiveProcessors;
+#endif
     }
 
     /* Add the debug port */
-    if (DebugPort != NULL) 
-    {    
+    if (DebugPort != NULL)
+    {
         Status = ObReferenceObjectByHandle(DebugPort,
                                            PORT_ALL_ACCESS,
                                            LpcPortObjectType,
-                                           PreviousMode,    
+                                           PreviousMode,
                                            (PVOID*)&pDebugPort,
                                            NULL);
-        if (!NT_SUCCESS(Status)) 
+        if (!NT_SUCCESS(Status))
         {
                 DPRINT1("Failed to reference the debug port: Status: 0x%x\n", Status);
-                goto exitdereferenceobjects;
+                goto Cleanup;
         }
     }
 
     /* Add the exception port */
-    if (ExceptionPort != NULL) 
+    if (ExceptionPort != NULL)
     {
         Status = ObReferenceObjectByHandle(ExceptionPort,
                                            PORT_ALL_ACCESS,
@@ -242,19 +256,19 @@ PspCreateProcess(OUT PHANDLE ProcessHandle,
                                            PreviousMode,
                                            (PVOID*)&pExceptionPort,
                                            NULL);
-        
-        if (!NT_SUCCESS(Status)) 
+
+        if (!NT_SUCCESS(Status))
         {
             DPRINT1("Failed to reference the exception port: Status: 0x%x\n", Status);
-            goto exitdereferenceobjects;
+            goto Cleanup;
         }
     }
 
     /* Add the Section */
-    if (SectionHandle != NULL) 
+    if (SectionHandle != NULL)
     {
         Status = ObReferenceObjectByHandle(SectionHandle,
-                                           0,
+                                           SECTION_MAP_EXECUTE,
                                            MmSectionObjectType,
                                            PreviousMode,
                                            (PVOID*)&SectionObject,
@@ -262,7 +276,7 @@ PspCreateProcess(OUT PHANDLE ProcessHandle,
         if (!NT_SUCCESS(Status))
         {
             DPRINT1("Failed to reference process image section: Status: 0x%x\n", Status);
-            goto exitdereferenceobjects;
+            goto Cleanup;
         }
     }
 
@@ -277,125 +291,122 @@ PspCreateProcess(OUT PHANDLE ProcessHandle,
                             0,
                             0,
                             (PVOID*)&Process);
-    
-    if (!NT_SUCCESS(Status)) 
+
+    if (!NT_SUCCESS(Status))
     {
         DPRINT1("Failed to create process object, Status: 0x%x\n", Status);
-        goto exitdereferenceobjects;
+        goto Cleanup;
     }
-  
+
     /* Clean up the Object */
     DPRINT("Cleaning Process Object\n");
     RtlZeroMemory(Process, sizeof(EPROCESS));
-    
+
     /* Inherit stuff from the Parent since we now have the object created */
-    if (pParentProcess) 
+    if (pParentProcess)
     {
         Process->InheritedFromUniqueProcessId = pParentProcess->UniqueProcessId;
-        Process->SessionId = pParentProcess->SessionId;
+        Process->Session = pParentProcess->Session;
     }
-    
-    /* FIXME: Set up the Quota Block from the Parent
-    PspInheritQuota(Parent, Process); */
-               
+
+    /* Set up the Quota Block from the Parent */
+    PspInheritQuota(Process, pParentProcess);
+
     /* FIXME: Set up Dos Device Map from the Parent
     ObInheritDeviceMap(Parent, Process) */
-               
+
     /* Set the Process' LPC Ports */
     Process->DebugPort = pDebugPort;
     Process->ExceptionPort = pExceptionPort;
-    
+
     /* Setup the Lock Event */
     DPRINT("Initialzing Process Lock\n");
     KeInitializeEvent(&Process->LockEvent, SynchronizationEvent, FALSE);
-    
+
     /* Setup the Thread List Head */
     DPRINT("Initialzing Process ThreadListHead\n");
     InitializeListHead(&Process->ThreadListHead);
-        
+
     /* Create or Clone the Handle Table */
     DPRINT("Initialzing Process Handle Table\n");
     ObCreateHandleTable(pParentProcess, InheritObjectTable,  Process);
     DPRINT("Handle Table: %x\n", Process->ObjectTable);
-   
+
     /* Set Process's Directory Base */
     DPRINT("Initialzing Process Directory Base\n");
-    MmCopyMmInfo(pParentProcess ? pParentProcess : PsInitialSystemProcess, 
+    MmCopyMmInfo(pParentProcess ? pParentProcess : PsInitialSystemProcess,
                  Process,
                  &DirectoryTableBase);
-   
+
     /* Now initialize the Kernel Process */
     DPRINT("Initialzing Kernel Process\n");
     KeInitializeProcess(&Process->Pcb,
-                        PROCESS_PRIO_NORMAL,
+                        PROCESS_PRIORITY_NORMAL,
                         Affinity,
                         DirectoryTableBase);
-      
+
     /* Duplicate Parent Token */
     DPRINT("Initialzing Process Token\n");
     Status = PspInitializeProcessSecurity(Process, pParentProcess);
-    if (!NT_SUCCESS(Status)) 
+    if (!NT_SUCCESS(Status))
     {
         DbgPrint("PspInitializeProcessSecurity failed (Status %x)\n", Status);
-        ObDereferenceObject(Process);
-        goto exitdereferenceobjects;
+        goto Cleanup;
     }
-    
+
     /* Create the Process' Address Space */
     DPRINT("Initialzing Process Address Space\n");
     Status = MmCreateProcessAddressSpace(Process, SectionObject);
-    if (!NT_SUCCESS(Status)) 
+    if (!NT_SUCCESS(Status))
     {
         DPRINT1("Failed to create Address Space\n");
-        ObDereferenceObject(Process);
-        goto exitdereferenceobjects;
+        goto Cleanup;
     }
-    
-    if (SectionObject) 
+
+    if (SectionObject)
     {
         /* Map the System Dll */
         DPRINT("Mapping System DLL\n");
-        LdrpMapSystemDll(Process, NULL);
+        PspMapSystemDll(Process, NULL);
     }
 
     /* Create a handle for the Process */
     DPRINT("Initialzing Process CID Handle\n");
-    Status = PsCreateCidHandle(Process,
-                               PsProcessType,
-                               &Process->UniqueProcessId);
-    if(!NT_SUCCESS(Status)) 
+    CidEntry.u1.Object = Process;
+    CidEntry.u2.GrantedAccess = 0;
+    Process->UniqueProcessId = ExCreateHandle(PspCidTable, &CidEntry);
+    DPRINT("Created CID: %d\n", Process->UniqueProcessId);
+    if(!Process->UniqueProcessId)
     {
-        DPRINT1("Failed to create CID handle (unique process ID)! Status: 0x%x\n", Status);
-        ObDereferenceObject(Process);
-        goto exitdereferenceobjects;
-   }
-   
+        DPRINT1("Failed to create CID handle\n");
+        Status = STATUS_UNSUCCESSFUL; /* FIXME - what error should we return? */
+        goto Cleanup;
+    }
+
     /* FIXME: Insert into Job Object */
 
     /* Create PEB only for User-Mode Processes */
-    if (pParentProcess) 
+    if (pParentProcess)
     {
         DPRINT("Creating PEB\n");
         Status = MmCreatePeb(Process);
-        if (!NT_SUCCESS(Status)) 
+        if (!NT_SUCCESS(Status))
         {
             DbgPrint("NtCreateProcess() Peb creation failed: Status %x\n",Status);
-            ObDereferenceObject(Process);
-            goto exitdereferenceobjects;
+            goto Cleanup;
         }
-        
-        /* Let's take advantage of this time to kill the reference too */
-        ObDereferenceObject(pParentProcess);
     }
 
     /* W00T! The process can now be activated */
     DPRINT("Inserting into Active Process List\n");
     ExAcquireFastMutex(&PspActiveProcessMutex);
-    InsertTailList(&PsActiveProcessHead, &Process->ProcessListEntry);
+    InsertTailList(&PsActiveProcessHead, &Process->ActiveProcessLinks);
     ExReleaseFastMutex(&PspActiveProcessMutex);
     
+    ProcessCreated = TRUE;
+
     /* FIXME: SeCreateAccessStateEx */
-               
+
     /* Insert the Process into the Object Directory */
     DPRINT("Inserting Process Object\n");
     Status = ObInsertObject(Process,
@@ -404,38 +415,35 @@ PspCreateProcess(OUT PHANDLE ProcessHandle,
                             0,
                             NULL,
                             &hProcess);
-    if (!NT_SUCCESS(Status)) 
-    {
-        DPRINT1("Could not get a handle to the Process Object\n");
-        ObDereferenceObject(Process);
-        goto exitdereferenceobjects;
-    }
-               
-    DPRINT("Done. Returning handle: %x\n", hProcess);
-    if (NT_SUCCESS(Status)) 
+    if (NT_SUCCESS(Status))
     {
-        _SEH_TRY 
+        /* Set the Creation Time */
+        KeQuerySystemTime(&Process->CreateTime);
+
+        DPRINT("Done. Returning handle: %x\n", hProcess);
+        _SEH_TRY
         {
-            *ProcessHandle = hProcess;
-        } 
-        _SEH_HANDLE 
+           *ProcessHandle = hProcess;
+        }
+        _SEH_HANDLE
         {
-            Status = _SEH_GetExceptionCode();
+           Status = _SEH_GetExceptionCode();
         } _SEH_END;
+        /* FIXME: ObGetObjectSecurity(Process, &SecurityDescriptor)
+                  SeAccessCheck
+        */
     }
-    
-    /* FIXME: ObGetObjectSecurity(Process, &SecurityDescriptor)
-              SeAccessCheck
-    */
-   ObReferenceObject(Process);
-   ObReferenceObject(Process);
-   return Status;
-   
-exitdereferenceobjects:
-    if(SectionObject != NULL) ObDereferenceObject(SectionObject);
-    if(pExceptionPort != NULL) ObDereferenceObject(pExceptionPort);
-    if(pDebugPort != NULL) ObDereferenceObject(pDebugPort);
+
+Cleanup:
     if(pParentProcess != NULL) ObDereferenceObject(pParentProcess);
+    if(SectionObject != NULL) ObDereferenceObject(SectionObject);
+    if (!ProcessCreated)
+    {
+        if(pExceptionPort != NULL) ObDereferenceObject(pExceptionPort);
+        if(pDebugPort != NULL) ObDereferenceObject(pDebugPort);
+        if(Process != NULL) ObDereferenceObject(Process);
+    }
+
     return Status;
 }
 
@@ -444,7 +452,7 @@ exitdereferenceobjects:
 /*
  * @implemented
  */
-NTSTATUS 
+NTSTATUS
 STDCALL
 PsCreateSystemProcess(PHANDLE ProcessHandle,
                       ACCESS_MASK DesiredAccess,
@@ -463,30 +471,93 @@ PsCreateSystemProcess(PHANDLE ProcessHandle,
 /*
  * @implemented
  */
-NTSTATUS 
+NTSTATUS
 STDCALL
 PsLookupProcessByProcessId(IN HANDLE ProcessId,
                            OUT PEPROCESS *Process)
 {
-   PHANDLE_TABLE_ENTRY CidEntry;
-   PEPROCESS FoundProcess;
+    PHANDLE_TABLE_ENTRY CidEntry;
+    PEPROCESS FoundProcess;
+    NTSTATUS Status = STATUS_INVALID_PARAMETER;
+    PAGED_CODE();
+    
+    KeEnterCriticalRegion();
 
-   PAGED_CODE();
+    /* Get the CID Handle Entry */
+    if ((CidEntry = ExMapHandleToPointer(PspCidTable,
+                                         ProcessId)))
+    {
+        /* Get the Process */
+        FoundProcess = CidEntry->u1.Object;
 
-   ASSERT(Process);
+        /* Make sure it's really a process */
+        if (FoundProcess->Pcb.Header.Type == ProcessObject)
+        {
+            /* Reference and return it */
+            ObReferenceObject(FoundProcess);
+            *Process = FoundProcess;
+            Status = STATUS_SUCCESS;
+        }
 
-   CidEntry = PsLookupCidHandle(ProcessId, PsProcessType, (PVOID*)&FoundProcess);
-   if(CidEntry != NULL)
-   {
-       ObReferenceObject(FoundProcess);
+        /* Unlock the Entry */
+        ExUnlockHandleTableEntry(PspCidTable, CidEntry);
+    }
+    
+    KeLeaveCriticalRegion();
 
-        PsUnlockCidHandle(CidEntry);
+    /* Return to caller */
+    return Status;
+}
 
-        *Process = FoundProcess;
-        return STATUS_SUCCESS;
+/*
+ * @implemented
+ */
+NTSTATUS
+STDCALL
+PsLookupProcessThreadByCid(IN PCLIENT_ID Cid,
+                           OUT PEPROCESS *Process OPTIONAL,
+                           OUT PETHREAD *Thread)
+{
+    PHANDLE_TABLE_ENTRY CidEntry;
+    PETHREAD FoundThread;
+    NTSTATUS Status = STATUS_INVALID_CID;
+    PAGED_CODE();
+    
+    KeEnterCriticalRegion();
+
+    /* Get the CID Handle Entry */
+    if ((CidEntry = ExMapHandleToPointer(PspCidTable,
+                                          Cid->UniqueThread)))
+    {
+        /* Get the Process */
+        FoundThread = CidEntry->u1.Object;
+
+        /* Make sure it's really a thread and this process' */
+        if ((FoundThread->Tcb.DispatcherHeader.Type == ThreadObject) &&
+            (FoundThread->Cid.UniqueProcess == Cid->UniqueProcess))
+        {
+            /* Reference and return it */
+            ObReferenceObject(FoundThread);
+            *Thread = FoundThread;
+            Status = STATUS_SUCCESS;
+
+            /* Check if we should return the Process too */
+            if (Process)
+            {
+                /* Return it and reference it */
+                *Process = FoundThread->ThreadsProcess;
+                ObReferenceObject(*Process);
+            }
+        }
+
+        /* Unlock the Entry */
+        ExUnlockHandleTableEntry(PspCidTable, CidEntry);
     }
+    
+    KeLeaveCriticalRegion();
 
-    return STATUS_INVALID_PARAMETER;
+    /* Return to caller */
+    return Status;
 }
 
 /*
@@ -497,7 +568,7 @@ PsLookupProcessByProcessId(IN HANDLE ProcessId,
 PEPROCESS STDCALL
 IoGetCurrentProcess(VOID)
 {
-   if (PsGetCurrentThread() == NULL || 
+   if (PsGetCurrentThread() == NULL ||
        PsGetCurrentThread()->Tcb.ApcState.Process == NULL)
      {
        return(PsInitialSystemProcess);
@@ -546,7 +617,7 @@ BOOLEAN
 STDCALL
 PsGetProcessExitProcessCalled(PEPROCESS Process)
 {
-    return Process->ExitProcessCalled; 
+    return Process->ProcessExiting;
 }
 
 /*
@@ -635,7 +706,7 @@ ULONG
 STDCALL
 PsGetCurrentProcessSessionId(VOID)
 {
-    return PsGetCurrentProcess()->SessionId;
+    return PsGetCurrentProcess()->Session;
 }
 
 /*
@@ -665,7 +736,21 @@ HANDLE
 STDCALL
 PsGetProcessSessionId(PEPROCESS Process)
 {
-    return (HANDLE)Process->SessionId;
+    return (HANDLE)Process->Session;
+}
+
+struct _W32THREAD*
+STDCALL
+PsGetWin32Thread(VOID)
+{
+    return(PsGetCurrentThread()->Tcb.Win32Thread);
+}
+
+struct _W32PROCESS*
+STDCALL
+PsGetWin32Process(VOID)
+{
+    return (struct _W32PROCESS*)PsGetCurrentProcess()->Win32Process;
 }
 
 /*
@@ -700,7 +785,7 @@ PsIsProcessBeingDebugged(PEPROCESS Process)
 
 /*
  * @implemented
- */                       
+ */
 VOID
 STDCALL
 PsSetProcessPriorityClass(PEPROCESS Process,
@@ -711,7 +796,7 @@ PsSetProcessPriorityClass(PEPROCESS Process,
 
 /*
  * @implemented
- */                       
+ */
 VOID
 STDCALL
 PsSetProcessSecurityPort(PEPROCESS Process,
@@ -736,12 +821,24 @@ PsSetProcessWin32Process(PEPROCESS Process,
  */
 VOID
 STDCALL
-PsSetProcessWin32WindowStation(PEPROCESS Process,
-                               PVOID WindowStation)
+PsSetProcessWindowStation(PEPROCESS Process,
+                          PVOID WindowStation)
 {
     Process->Win32WindowStation = WindowStation;
 }
 
+/*
+ * @unimplemented
+ */
+NTSTATUS
+STDCALL
+PsSetProcessPriorityByClass(IN PEPROCESS Process,
+                            IN ULONG Type)
+{
+    UNIMPLEMENTED;
+    return STATUS_NOT_IMPLEMENTED;
+}
+
 /*
  * FUNCTION: Creates a process.
  * ARGUMENTS:
@@ -765,7 +862,7 @@ PsSetProcessWin32WindowStation(PEPROCESS Process,
  *
  * @implemented
  */
-NTSTATUS 
+NTSTATUS
 STDCALL
 NtCreateProcess(OUT PHANDLE ProcessHandle,
                 IN ACCESS_MASK DesiredAccess,
@@ -778,17 +875,15 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
 {
     KPROCESSOR_MODE PreviousMode  = ExGetPreviousMode();
     NTSTATUS Status = STATUS_SUCCESS;
-   
+
     PAGED_CODE();
-     
-    /* Check parameters */ 
+
+    /* Check parameters */
     if(PreviousMode != KernelMode)
     {
         _SEH_TRY
         {
-            ProbeForWrite(ProcessHandle,
-                          sizeof(HANDLE),
-                          sizeof(ULONG));
+            ProbeForWriteHandle(ProcessHandle);
         }
         _SEH_HANDLE
         {
@@ -798,7 +893,7 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
 
         if(!NT_SUCCESS(Status)) return Status;
     }
-   
+
     /* Make sure there's a parent process */
     if(ParentProcess == NULL)
     {
@@ -817,7 +912,7 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
                                   DebugPort,
                                   ExceptionPort);
     }
-   
+
     /* Return Status */
     return Status;
 }
@@ -825,30 +920,76 @@ NtCreateProcess(OUT PHANDLE ProcessHandle,
 /*
  * @implemented
  */
-NTSTATUS 
+NTSTATUS
 STDCALL
 NtOpenProcess(OUT PHANDLE ProcessHandle,
               IN  ACCESS_MASK DesiredAccess,
               IN  POBJECT_ATTRIBUTES ObjectAttributes,
               IN  PCLIENT_ID ClientId)
 {
-    KPROCESSOR_MODE PreviousMode  = ExGetPreviousMode();
-    NTSTATUS Status = STATUS_INVALID_PARAMETER;
-    PEPROCESS Process;
+    KPROCESSOR_MODE PreviousMode;
+    CLIENT_ID SafeClientId;
+    ULONG Attributes = 0;
+    HANDLE hProcess;
+    BOOLEAN HasObjectName = FALSE;
     PETHREAD Thread = NULL;
-   
-    DPRINT("NtOpenProcess(ProcessHandle %x, DesiredAccess %x, "
-           "ObjectAttributes %x, ClientId %x { UniP %d, UniT %d })\n",
-           ProcessHandle, DesiredAccess, ObjectAttributes, ClientId,
-           ClientId->UniqueProcess, ClientId->UniqueThread);
+    PEPROCESS Process = NULL;
+    NTSTATUS Status = STATUS_SUCCESS;
+
     PAGED_CODE();
-        
+
+    PreviousMode = KeGetPreviousMode();
+
+    /* Probe the paraemeters */
+    if(PreviousMode != KernelMode)
+    {
+        _SEH_TRY
+        {
+            ProbeForWriteHandle(ProcessHandle);
+
+            if(ClientId != NULL)
+            {
+                ProbeForRead(ClientId,
+                             sizeof(CLIENT_ID),
+                             sizeof(ULONG));
+
+                SafeClientId = *ClientId;
+                ClientId = &SafeClientId;
+            }
+
+            /* just probe the object attributes structure, don't capture it
+               completely. This is done later if necessary */
+            ProbeForRead(ObjectAttributes,
+                         sizeof(OBJECT_ATTRIBUTES),
+                         sizeof(ULONG));
+            HasObjectName = (ObjectAttributes->ObjectName != NULL);
+            Attributes = ObjectAttributes->Attributes;
+        }
+        _SEH_HANDLE
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+
+        if(!NT_SUCCESS(Status)) return Status;
+    }
+    else
+    {
+        HasObjectName = (ObjectAttributes->ObjectName != NULL);
+        Attributes = ObjectAttributes->Attributes;
+    }
+
+    if (HasObjectName && ClientId != NULL)
+    {
+        /* can't pass both, n object name and a client id */
+        return STATUS_INVALID_PARAMETER_MIX;
+    }
+
     /* Open by name if one was given */
     DPRINT("Checking type\n");
-    if (ObjectAttributes->ObjectName)
+    if (HasObjectName)
     {
-        /* Open it */    
+        /* Open it */
         DPRINT("Opening by name\n");
         Status = ObOpenObjectByName(ObjectAttributes,
                                     PsProcessType,
@@ -856,64 +997,77 @@ NtOpenProcess(OUT PHANDLE ProcessHandle,
                                     PreviousMode,
                                     DesiredAccess,
                                     NULL,
-                                    ProcessHandle);
-                                        
-        if (Status != STATUS_SUCCESS)
+                                    &hProcess);
+
+        if (!NT_SUCCESS(Status))
         {
             DPRINT1("Could not open object by name\n");
         }
-        
-        /* Return Status */
-        DPRINT("Found: %x\n", ProcessHandle);
-        return(Status);
     }
-    else if (ClientId)
+    else if (ClientId != NULL)
     {
         /* Open by Thread ID */
         if (ClientId->UniqueThread)
         {
             /* Get the Process */
-            DPRINT("Opening by Thread ID\n");
+            DPRINT("Opening by Thread ID: %x\n", ClientId->UniqueThread);
             Status = PsLookupProcessThreadByCid(ClientId,
                                                 &Process,
                                                 &Thread);
-            DPRINT("Found: %x\n", Process);
-        } 
-        else 
+        }
+        else
         {
             /* Get the Process */
-            DPRINT("Opening by Process ID\n");
+            DPRINT("Opening by Process ID: %x\n", ClientId->UniqueProcess);
             Status = PsLookupProcessByProcessId(ClientId->UniqueProcess,
                                                 &Process);
-            DPRINT("Found: %x\n", Process);
         }
-       
+
         if(!NT_SUCCESS(Status))
         {
             DPRINT1("Failure to find process\n");
             return Status;
         }
-       
+
         /* Open the Process Object */
         Status = ObOpenObjectByPointer(Process,
-                                       ObjectAttributes->Attributes,
+                                       Attributes,
                                        NULL,
-                                       0,
+                                       DesiredAccess,
                                        PsProcessType,
                                        PreviousMode,
-                                       ProcessHandle);
+                                       &hProcess);
         if(!NT_SUCCESS(Status))
         {
             DPRINT1("Failure to open process\n");
         }
-                                      
+
         /* Dereference the thread if we used it */
         if (Thread) ObDereferenceObject(Thread);
-        
+
         /* Dereference the Process */
         ObDereferenceObject(Process);
     }
-    
+    else
+    {
+        /* neither an object name nor a client id was passed */
+        return STATUS_INVALID_PARAMETER_MIX;
+    }
+
+    /* Write back the handle */
+    if(NT_SUCCESS(Status))
+    {
+        _SEH_TRY
+        {
+            *ProcessHandle = hProcess;
+        }
+        _SEH_HANDLE
+        {
+            Status = _SEH_GetExceptionCode();
+        }
+        _SEH_END;
+    }
+
     return Status;
 }
 /* EOF */