- Implement ProcessQuotaLimits case for NtQueryInformationProcess. Based on Dmitry...
[reactos.git] / reactos / ntoskrnl / ps / query.c
index f4c6b2c..e00a0cd 100644 (file)
 
 #include <ntoskrnl.h>
 #define NDEBUG
-#include <internal/debug.h>
+#include <debug.h>
 
 /* Include Information Class Tables */
 #include "internal/ps_i.h"
 
 /* Debugging Level */
-ULONG PspTraceLevel = 0; //PS_KILL_DEBUG | PS_SECURITY_DEBUG;
+ULONG PspTraceLevel = 0;
 
 /* PRIVATE FUNCTIONS *********************************************************/
 
-/* FIXME:
- * This entire API is messed up because:
- * 1) Directly pokes SECTION_OBJECT/FILE_OBJECT without special reffing.
- * 2) Ignores SeAuditProcessImageFileName stuff added in XP (and ROS).
- * 3) Doesn't use ObQueryNameString.
- */
 NTSTATUS
 NTAPI
-PspGetImagePath(IN PEPROCESS Process,
-                OUT PUNICODE_STRING DstPath,
-                IN ULONG ProcessInformationLength)
+PsReferenceProcessFilePointer(IN PEPROCESS Process,
+                              OUT PFILE_OBJECT *FileObject)
 {
-    NTSTATUS Status;
-    ULONG ImagePathLen = 0;
-    PROS_SECTION_OBJECT Section;
-    PWSTR SrcBuffer = NULL, DstBuffer = (PWSTR)(DstPath + 1);
+    PSECTION Section;
+    PAGED_CODE();
 
-    Section = (PROS_SECTION_OBJECT)Process->SectionObject;
-    if ((Section)&& (Section->FileObject))
-    {
-        /* FIXME - check for SEC_IMAGE and/or SEC_FILE instead
-        of relying on FileObject being != NULL? */
-        SrcBuffer = Section->FileObject->FileName.Buffer;
-        if (SrcBuffer) ImagePathLen = Section->FileObject->FileName.Length;
-    }
+    /* Lock the process */
+    ExAcquireRundownProtection(&Process->RundownProtect);
 
-    if (ProcessInformationLength < (sizeof(UNICODE_STRING) +
-                                    ImagePathLen +
-                                    sizeof(WCHAR)))
+    /* Get the section */
+    Section = Process->SectionObject;
+    if (Section)
     {
-        return STATUS_INFO_LENGTH_MISMATCH;
+        /* Get the file object and reference it */
+        *FileObject = MmGetFileObjectForSection((PVOID)Section);
+        ObReferenceObject(*FileObject);
     }
 
-    Status = STATUS_SUCCESS;
-    _SEH_TRY
-    {
-        /* copy the string manually, don't use RtlCopyUnicodeString with DstPath! */
-        DstPath->Length = ImagePathLen;
-        DstPath->MaximumLength = ImagePathLen + sizeof(WCHAR);
-        DstPath->Buffer = DstBuffer;
-        if (ImagePathLen) RtlCopyMemory(DstBuffer, SrcBuffer, ImagePathLen);
-        DstBuffer[ImagePathLen / sizeof(WCHAR)] = L'\0';
-    }
-    _SEH_HANDLE
-    {
-        Status = _SEH_GetExceptionCode();
-    }
-    _SEH_END;
+    /* Release the protection */
+    ExReleaseRundownProtection(&Process->RundownProtect);
 
     /* Return status */
-    return Status;
+    return Section ? STATUS_SUCCESS : STATUS_UNSUCCESSFUL;
 }
 
 /* PUBLIC FUNCTIONS **********************************************************/
@@ -94,15 +68,20 @@ NtQueryInformationProcess(IN HANDLE ProcessHandle,
     PPROCESS_BASIC_INFORMATION ProcessBasicInfo =
         (PPROCESS_BASIC_INFORMATION)ProcessInformation;
     PKERNEL_USER_TIMES ProcessTime = (PKERNEL_USER_TIMES)ProcessInformation;
+    PPROCESS_PRIORITY_CLASS PsPriorityClass = (PPROCESS_PRIORITY_CLASS)ProcessInformation;
     ULONG HandleCount;
     PPROCESS_SESSION_INFORMATION SessionInfo =
         (PPROCESS_SESSION_INFORMATION)ProcessInformation;
     PVM_COUNTERS VmCounters = (PVM_COUNTERS)ProcessInformation;
+    PIO_COUNTERS IoCounters = (PIO_COUNTERS)ProcessInformation;
+    PQUOTA_LIMITS QuotaLimits = (PQUOTA_LIMITS)ProcessInformation;
     PROCESS_DEVICEMAP_INFORMATION DeviceMap;
+    PUNICODE_STRING ImageName;
     ULONG Cookie;
     PAGED_CODE();
 
     /* Check validity of Information Class */
+#if 0
     Status = DefaultQueryInfoBufferCheck(ProcessInformationClass,
                                          PsProcessInfoClass,
                                          RTL_NUMBER_OF(PsProcessInfoClass),
@@ -111,20 +90,10 @@ NtQueryInformationProcess(IN HANDLE ProcessHandle,
                                          ReturnLength,
                                          PreviousMode);
     if (!NT_SUCCESS(Status)) return Status;
+#endif
 
-    /* Check if this isn't the cookie class */
-    if(ProcessInformationClass != ProcessCookie)
-    {
-        /* Reference the process */
-        Status = ObReferenceObjectByHandle(ProcessHandle,
-                                           PROCESS_QUERY_INFORMATION,
-                                           PsProcessType,
-                                           PreviousMode,
-                                           (PVOID*)&Process,
-                                           NULL);
-        if (!NT_SUCCESS(Status)) return Status;
-    }
-    else if(ProcessHandle != NtCurrentProcess())
+    if((ProcessInformationClass == ProcessCookie) &&
+        (ProcessHandle != NtCurrentProcess()))
     {
         /*
          * Retreiving the process cookie is only allowed for the calling process
@@ -140,41 +109,176 @@ NtQueryInformationProcess(IN HANDLE ProcessHandle,
         /* Basic process information */
         case ProcessBasicInformation:
 
+            /* Set return length */
+            Length = sizeof(PROCESS_BASIC_INFORMATION);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
             /* Protect writes with SEH */
-            _SEH_TRY
+            _SEH2_TRY
             {
                 /* Write all the information from the EPROCESS/KPROCESS */
                 ProcessBasicInfo->ExitStatus = Process->ExitStatus;
                 ProcessBasicInfo->PebBaseAddress = Process->Peb;
                 ProcessBasicInfo->AffinityMask = Process->Pcb.Affinity;
-                ProcessBasicInfo->UniqueProcessId = (ULONG)Process->
+                ProcessBasicInfo->UniqueProcessId = (ULONG_PTR)Process->
                                                     UniqueProcessId;
                 ProcessBasicInfo->InheritedFromUniqueProcessId =
                     (ULONG)Process->InheritedFromUniqueProcessId;
                 ProcessBasicInfo->BasePriority = Process->Pcb.BasePriority;
 
-                /* Set return length */
-                Length = sizeof(PROCESS_BASIC_INFORMATION);
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                 /* Get exception code */
-                Status = _SEH_GetExceptionCode();
+                Status = _SEH2_GetExceptionCode();
             }
-            _SEH_END;
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
             break;
 
-        /* Quote limits and I/O Counters: not implemented */
+        /* Process quota limits */
         case ProcessQuotaLimits:
+
+            Length = sizeof(QUOTA_LIMITS);
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Indicate success */
+            Status = STATUS_SUCCESS;
+
+            _SEH2_TRY
+            {
+                /* Set max/min working set sizes */
+                QuotaLimits->MaximumWorkingSetSize =
+                        Process->Vm.MaximumWorkingSetSize << PAGE_SHIFT;
+                QuotaLimits->MinimumWorkingSetSize =
+                        Process->Vm.MinimumWorkingSetSize << PAGE_SHIFT;
+
+                /* Set default time limits */
+                QuotaLimits->TimeLimit.LowPart = (ULONG)-1;
+                QuotaLimits->TimeLimit.HighPart = (ULONG)-1;
+
+                /* Is quota block a default one? */
+                if (Process->QuotaBlock == &PspDefaultQuotaBlock)
+                {
+                    /* Set default pools and pagefile limits */
+                    QuotaLimits->PagedPoolLimit = (SIZE_T)-1;
+                    QuotaLimits->NonPagedPoolLimit = (SIZE_T)-1;
+                    QuotaLimits->PagefileLimit = (SIZE_T)-1;
+                }
+                else
+                {
+                    /* Get limits from non-default quota block */
+                    QuotaLimits->PagedPoolLimit =
+                        Process->QuotaBlock->QuotaEntry[PagedPool].Limit;
+                    QuotaLimits->NonPagedPoolLimit =
+                        Process->QuotaBlock->QuotaEntry[NonPagedPool].Limit;
+                    QuotaLimits->PagefileLimit =
+                        Process->QuotaBlock->QuotaEntry[2].Limit;
+                }
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
+            break;
+
         case ProcessIoCounters:
-            Status = STATUS_NOT_IMPLEMENTED;
+
+            Length = sizeof(IO_COUNTERS);
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            _SEH2_TRY
+            {
+                IoCounters->ReadOperationCount = Process->ReadOperationCount.QuadPart;
+                IoCounters->ReadTransferCount = Process->ReadTransferCount.QuadPart;
+                IoCounters->WriteOperationCount = Process->WriteOperationCount.QuadPart;
+                IoCounters->WriteTransferCount = Process->WriteTransferCount.QuadPart;
+                IoCounters->OtherOperationCount = Process->OtherOperationCount.QuadPart;
+                IoCounters->OtherTransferCount = Process->OtherTransferCount.QuadPart;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Ignore exception */
+            }
+            _SEH2_END;
+
+            /* Set status to success in any case */
+            Status = STATUS_SUCCESS;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
             break;
 
         /* Timing */
         case ProcessTimes:
 
+            /* Set the return length */
+            Length = sizeof(KERNEL_USER_TIMES);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
             /* Protect writes with SEH */
-            _SEH_TRY
+            _SEH2_TRY
             {
                 /* Copy time information from EPROCESS/KPROCESS */
                 ProcessTime->CreateTime = Process->CreateTime;
@@ -183,86 +287,154 @@ NtQueryInformationProcess(IN HANDLE ProcessHandle,
                 ProcessTime->KernelTime.QuadPart = Process->Pcb.KernelTime *
                                                    100000LL;
                 ProcessTime->ExitTime = Process->ExitTime;
-
-                /* Set the return length */
-                Length = sizeof(KERNEL_USER_TIMES);
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                 /* Get exception code */
-                Status = _SEH_GetExceptionCode();
+                Status = _SEH2_GetExceptionCode();
             }
-            _SEH_END;
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
             break;
 
         /* Process Debug Port */
         case ProcessDebugPort:
 
+            /* Set return length */
+            Length = sizeof(HANDLE);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
             /* Protect write with SEH */
-            _SEH_TRY
+            _SEH2_TRY
             {
                 /* Return whether or not we have a debug port */
                 *(PHANDLE)ProcessInformation = (Process->DebugPort ?
                                                 (HANDLE)-1 : NULL);
-
-                /* Set the return length*/
-                Length = sizeof(HANDLE);
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                 /* Get exception code */
-                Status = _SEH_GetExceptionCode();
+                Status = _SEH2_GetExceptionCode();
             }
-            _SEH_END;
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
             break;
 
         /* LDT, WS and VDM Information: not implemented */
         case ProcessLdtInformation:
         case ProcessWorkingSetWatch:
         case ProcessWx86Information:
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
+            DPRINT1("Not implemented: %lx\n", ProcessInformationClass);
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
             Status = STATUS_NOT_IMPLEMENTED;
             break;
 
         case ProcessHandleCount:
 
+            /* Set the return length*/
+            Length = sizeof(ULONG);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
             /* Count the number of handles this process has */
-            HandleCount = ObpGetHandleCountByHandleTable(Process->ObjectTable);
+            HandleCount = ObGetProcessHandleCount(Process);
 
             /* Protect write in SEH */
-            _SEH_TRY
+            _SEH2_TRY
             {
                 /* Return the count of handles */
                 *(PULONG)ProcessInformation = HandleCount;
-
-                /* Set the return length*/
-                Length = sizeof(ULONG);
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                 /* Get the exception code */
-                Status = _SEH_GetExceptionCode();
+                Status = _SEH2_GetExceptionCode();
             }
-            _SEH_END;
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
             break;
 
         /* Session ID for the process */
         case ProcessSessionInformation:
 
+            /* Set the return length*/
+            Length = sizeof(PROCESS_SESSION_INFORMATION);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
             /* Enter SEH for write safety */
-            _SEH_TRY
+            _SEH2_TRY
             {
                 /* Write back the Session ID */
                 SessionInfo->SessionId = Process->Session;
-
-                /* Set the return length */
-                Length = sizeof(PROCESS_SESSION_INFORMATION);
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                 /* Get the exception code */
-                Status = _SEH_GetExceptionCode();
+                Status = _SEH2_GetExceptionCode();
             }
-            _SEH_END;
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
             break;
 
         /* WOW64: Not implemented */
@@ -273,8 +445,26 @@ NtQueryInformationProcess(IN HANDLE ProcessHandle,
         /* Virtual Memory Statistics */
         case ProcessVmCounters:
 
+            /* Set the return length */
+            Length = sizeof(VM_COUNTERS);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
             /* Enter SEH for write safety */
-            _SEH_TRY
+            _SEH2_TRY
             {
                 /* Return data from EPROCESS */
                 VmCounters->PeakVirtualSize = Process->PeakVirtualSize;
@@ -289,107 +479,227 @@ NtQueryInformationProcess(IN HANDLE ProcessHandle,
                 VmCounters->PagefileUsage = Process->QuotaUsage[2];
                 VmCounters->PeakPagefileUsage = Process->QuotaPeak[2];
 
-                /* Set the return length */
-                *ReturnLength = sizeof(VM_COUNTERS);
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                 /* Get the exception code */
-                Status = _SEH_GetExceptionCode();
+                Status = _SEH2_GetExceptionCode();
             }
-            _SEH_END;
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
             break;
 
         /* Hard Error Processing Mode */
         case ProcessDefaultHardErrorMode:
 
+            /* Set the return length*/
+            Length = sizeof(ULONG);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
             /* Enter SEH for writing back data */
-            _SEH_TRY
+            _SEH2_TRY
             {
                 /* Write the current processing mode */
                 *(PULONG)ProcessInformation = Process->
                                               DefaultHardErrorProcessing;
-
-                /* Set the return length */
-                Length = sizeof(ULONG);
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                 /* Get the exception code */
-                Status = _SEH_GetExceptionCode();
+                Status = _SEH2_GetExceptionCode();
             }
-            _SEH_END;
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
             break;
 
         /* Priority Boosting status */
         case ProcessPriorityBoost:
 
+            /* Set the return length*/
+            Length = sizeof(ULONG);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
             /* Enter SEH for writing back data */
-            _SEH_TRY
+            _SEH2_TRY
             {
                 /* Return boost status */
                 *(PULONG)ProcessInformation = Process->Pcb.DisableBoost ?
-                                              FALSE : TRUE;
-
-                /* Set the return length */
-                Length = sizeof(ULONG);
+                                              TRUE : FALSE;
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                 /* Get the exception code */
-                Status = _SEH_GetExceptionCode();
+                Status = _SEH2_GetExceptionCode();
             }
-            _SEH_END;
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
             break;
 
         /* DOS Device Map */
         case ProcessDeviceMap:
 
+            /* Set the return length*/
+            Length = sizeof(PROCESS_DEVICEMAP_INFORMATION);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
             /* Query the device map information */
             ObQueryDeviceMapInformation(Process, &DeviceMap);
 
             /* Enter SEH for writing back data */
-            _SEH_TRY
+            _SEH2_TRY
             {
                 *(PPROCESS_DEVICEMAP_INFORMATION)ProcessInformation = DeviceMap;
-
-                /* Set the return length */
-                Length = sizeof(PROCESS_DEVICEMAP_INFORMATION);
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                 /* Get the exception code */
-                Status = _SEH_GetExceptionCode();
+                Status = _SEH2_GetExceptionCode();
             }
-            _SEH_END;
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
             break;
 
         /* Priority class */
         case ProcessPriorityClass:
 
+            /* Set the return length*/
+            Length = sizeof(PROCESS_PRIORITY_CLASS);
+
+            if (ProcessInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
             /* Enter SEH for writing back data */
-            _SEH_TRY
+            _SEH2_TRY
             {
                 /* Return current priority class */
-                *(PUSHORT)ProcessInformation = Process->PriorityClass;
-
-                /* Set the return length */
-                Length = sizeof(USHORT);
+                PsPriorityClass->PriorityClass = Process->PriorityClass;
+                PsPriorityClass->Foreground = FALSE;
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                 /* Get the exception code */
-                Status = _SEH_GetExceptionCode();
+                Status = _SEH2_GetExceptionCode();
             }
-            _SEH_END;
+            _SEH2_END;
+
+            /* Dereference the process */
+            ObDereferenceObject(Process);
             break;
 
         case ProcessImageFileName:
 
+            /* Reference the process */
+            Status = ObReferenceObjectByHandle(ProcessHandle,
+                                               PROCESS_QUERY_INFORMATION,
+                                               PsProcessType,
+                                               PreviousMode,
+                                               (PVOID*)&Process,
+                                               NULL);
+            if (!NT_SUCCESS(Status)) break;
+
             /* Get the image path */
-            Status = PspGetImagePath(Process,
-                                     (PUNICODE_STRING)ProcessInformation,
-                                     ProcessInformationLength);
+            Status = SeLocateProcessImageName(Process, &ImageName);
+            if (NT_SUCCESS(Status))
+            {
+                /* Set return length */
+                Length = ImageName->MaximumLength +
+                         sizeof(OBJECT_NAME_INFORMATION);
+
+                /* Make sure it's large enough */
+                if (Length <= ProcessInformationLength)
+                {
+                    /* Enter SEH to protect write */
+                    _SEH2_TRY
+                    {
+                        /* Copy it */
+                        RtlCopyMemory(ProcessInformation,
+                                      ImageName,
+                                      Length);
+
+                        /* Update pointer */
+                        ((PUNICODE_STRING)ProcessInformation)->Buffer =
+                            (PWSTR)((PUNICODE_STRING)ProcessInformation + 1);
+                   }
+                    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+                    {
+                        /* Get the exception code */
+                        Status = _SEH2_GetExceptionCode();
+                    }
+                    _SEH2_END;
+                }
+                else
+                {
+                    /* Buffer too small */
+                    Status = STATUS_INFO_LENGTH_MISMATCH;
+                }
+
+                /* Free the image path */
+                ExFreePool(ImageName);
+            }
+            /* Dereference the process */
+            ObDereferenceObject(Process);
             break;
 
         /* Per-process security cookie */
@@ -398,7 +708,7 @@ NtQueryInformationProcess(IN HANDLE ProcessHandle,
             /* Get the current process and cookie */
             Process = PsGetCurrentProcess();
             Cookie = Process->Cookie;
-            if(!Cookie)
+            if (!Cookie)
             {
                 LARGE_INTEGER SystemTime;
                 ULONG NewCookie;
@@ -414,24 +724,24 @@ NtQueryInformationProcess(IN HANDLE ProcessHandle,
                 Cookie = InterlockedCompareExchange((LONG*)&Process->Cookie,
                                                     NewCookie,
                                                     Cookie);
-                if(!Cookie) Cookie = NewCookie;
+                if (!Cookie) Cookie = NewCookie;
 
                 /* Set return length */
                 Length = sizeof(ULONG);
             }
 
             /* Enter SEH to protect write */
-            _SEH_TRY
+            _SEH2_TRY
             {
                 /* Write back the cookie */
                 *(PULONG)ProcessInformation = Cookie;
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                 /* Get the exception code */
-                Status = _SEH_GetExceptionCode();
+                Status = _SEH2_GetExceptionCode();
             }
-            _SEH_END;
+            _SEH2_END;
             break;
 
         /* Not yet implemented, or unknown */
@@ -446,24 +756,23 @@ NtQueryInformationProcess(IN HANDLE ProcessHandle,
         case ProcessAffinityMask:
         case ProcessForegroundInformation:
         default:
+            DPRINT1("Unsupported or unimplemented: %lx\n", ProcessInformationClass);
             Status = STATUS_INVALID_INFO_CLASS;
     }
 
     /* Protect write with SEH */
-    _SEH_TRY
+    _SEH2_TRY
     {
         /* Check if caller wanted return length */
         if (ReturnLength) *ReturnLength = Length;
     }
-    _SEH_HANDLE
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
     {
         /* Get exception code */
-        Status = _SEH_GetExceptionCode();
+        Status = _SEH2_GetExceptionCode();
     }
-    _SEH_END;
+    _SEH2_END;
 
-    /* If we referenced the process, dereference it */
-    if(ProcessInformationClass != ProcessCookie) ObDereferenceObject(Process);
     return Status;
 }
 
@@ -484,10 +793,12 @@ NtSetInformationProcess(IN HANDLE ProcessHandle,
     HANDLE PortHandle = NULL;
     HANDLE TokenHandle = NULL;
     PROCESS_SESSION_INFORMATION SessionInfo = {0};
-    PEPORT ExceptionPort;
+    PROCESS_PRIORITY_CLASS PriorityClass = {0};
+    PVOID ExceptionPort;
     PAGED_CODE();
 
     /* Verify Information Class validity */
+#if 0
     Status = DefaultSetInfoBufferCheck(ProcessInformationClass,
                                        PsProcessInfoClass,
                                        RTL_NUMBER_OF(PsProcessInfoClass),
@@ -495,6 +806,7 @@ NtSetInformationProcess(IN HANDLE ProcessHandle,
                                        ProcessInformationLength,
                                        PreviousMode);
     if (!NT_SUCCESS(Status)) return Status;
+#endif
 
     /* Check what class this is */
     Access = PROCESS_SET_INFORMATION;
@@ -521,28 +833,28 @@ NtSetInformationProcess(IN HANDLE ProcessHandle,
     /* Check what kind of information class this is */
     switch (ProcessInformationClass)
     {
-        /* Quotas and priorities: not implemented */
-        case ProcessQuotaLimits:
-        case ProcessBasePriority:
-        case ProcessRaisePriority:
-            Status = STATUS_NOT_IMPLEMENTED;
-            break;
-
         /* Error/Exception Port */
         case ProcessExceptionPort:
 
+            /* Check buffer length */
+            if (ProcessInformationLength != sizeof(HANDLE))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
             /* Use SEH for capture */
-            _SEH_TRY
+            _SEH2_TRY
             {
                 /* Capture the handle */
                 PortHandle = *(PHANDLE)ProcessInformation;
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                 /* Get the exception code */
-                Status = _SEH_GetExceptionCode();
+                Status = _SEH2_GetExceptionCode();
             }
-            _SEH_END;
+            _SEH2_END;
             if (!NT_SUCCESS(Status)) break;
 
             /* Get the LPC Port */
@@ -568,19 +880,26 @@ NtSetInformationProcess(IN HANDLE ProcessHandle,
         /* Security Token */
         case ProcessAccessToken:
 
+            /* Check buffer length */
+            if (ProcessInformationLength != sizeof(PROCESS_ACCESS_TOKEN))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
             /* Use SEH for capture */
-            _SEH_TRY
+            _SEH2_TRY
             {
                 /* Save the token handle */
                 TokenHandle = ((PPROCESS_ACCESS_TOKEN)ProcessInformation)->
                                Token;
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                 /* Get the exception code */
-                Status = _SEH_GetExceptionCode();
+                Status = _SEH2_GetExceptionCode();
             }
-            _SEH_END;
+            _SEH2_END;
             if (!NT_SUCCESS(Status)) break;
 
             /* Assign the actual token */
@@ -590,36 +909,50 @@ NtSetInformationProcess(IN HANDLE ProcessHandle,
         /* Hard error processing */
         case ProcessDefaultHardErrorMode:
 
+            /* Check buffer length */
+            if (ProcessInformationLength != sizeof(ULONG))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
             /* Enter SEH for direct buffer read */
-            _SEH_TRY
+            _SEH2_TRY
             {
                 /* Update the current mode abd return the previous one */
                 InterlockedExchange((LONG*)&Process->DefaultHardErrorProcessing,
                                     *(PLONG)ProcessInformation);
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                 /* Get exception code */
-                Status = _SEH_GetExceptionCode();
+                Status = _SEH2_GetExceptionCode();
             }
-            _SEH_END;
+            _SEH2_END;
             break;
 
         /* Session ID */
         case ProcessSessionInformation:
 
+            /* Check buffer length */
+            if (ProcessInformationLength != sizeof(PROCESS_SESSION_INFORMATION))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
             /* Enter SEH for capture */
-            _SEH_TRY
+            _SEH2_TRY
             {
                 /* Capture the caller's buffer */
                 SessionInfo = *(PPROCESS_SESSION_INFORMATION)ProcessInformation;
             }
-            _SEH_HANDLE
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
             {
                 /* Get the exception code */
-                Status = _SEH_GetExceptionCode();
+                Status = _SEH2_GetExceptionCode();
             }
-            _SEH_END;
+            _SEH2_END;
             if (!NT_SUCCESS(Status)) break;
 
             /* Setting the session id requires the SeTcbPrivilege */
@@ -647,17 +980,17 @@ NtSetInformationProcess(IN HANDLE ProcessHandle,
                 KeAttachProcess(&Process->Pcb);
 
                 /* Enter SEH for write to user-mode PEB */
-                _SEH_TRY
+                _SEH2_TRY
                 {
                     /* Write the session ID */
                     Process->Peb->SessionId = SessionInfo.SessionId;
                 }
-                _SEH_HANDLE
+                _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
                 {
                     /* Get exception code */
-                    Status = _SEH_GetExceptionCode();
+                    Status = _SEH2_GetExceptionCode();
                 }
-                _SEH_END;
+                _SEH2_END;
 
                 /* Detach from the process */
                 KeDetachProcess();
@@ -667,11 +1000,59 @@ NtSetInformationProcess(IN HANDLE ProcessHandle,
             //PsUnlockProcess(Process);
             break;
 
-        /* Priority class: HACK! */
         case ProcessPriorityClass:
+
+            /* Check buffer length */
+            if (ProcessInformationLength != sizeof(PROCESS_PRIORITY_CLASS))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Enter SEH for capture */
+            _SEH2_TRY
+            {
+                /* Capture the caller's buffer */
+                PriorityClass = *(PPROCESS_PRIORITY_CLASS)ProcessInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Check for invalid PriorityClass value */
+            if (PriorityClass.PriorityClass > PROCESS_PRIORITY_CLASS_ABOVE_NORMAL)
+            {
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+
+            /* TODO: Check privileges */
+
+            /* Check if we have a job */
+            if (Process->Job)
+            {
+                DPRINT1("Jobs not yet supported\n");
+            }
+
+            /* Set process priority class */
+            Process->PriorityClass = PriorityClass.PriorityClass;
+
+            /* Set process priority mode (foreground or background) */
+            PsSetProcessPriorityByClass(Process,
+                                        !PriorityClass.Foreground ? PsProcessPriorityBackground :
+                                        PsProcessPriorityForeground);
+
+            Status = STATUS_SUCCESS;
             break;
 
         /* We currently don't implement any of these */
+        case ProcessQuotaLimits:
+        case ProcessBasePriority:
+        case ProcessRaisePriority:
         case ProcessLdtInformation:
         case ProcessLdtSize:
         case ProcessIoPortHandlers:
@@ -679,6 +1060,7 @@ NtSetInformationProcess(IN HANDLE ProcessHandle,
         case ProcessUserModeIOPL:
         case ProcessEnableAlignmentFaultFixup:
         case ProcessAffinityMask:
+            DPRINT1("Not implemented: %lx\n", ProcessInformationClass);
             Status = STATUS_NOT_IMPLEMENTED;
             break;
 
@@ -692,6 +1074,7 @@ NtSetInformationProcess(IN HANDLE ProcessHandle,
         case ProcessWow64Information:
         case ProcessDebugPort:
         default:
+            DPRINT1("Unsupported or unimplemented: %lx\n", ProcessInformationClass);
             Status = STATUS_INVALID_INFO_CLASS;
     }
 
@@ -701,7 +1084,7 @@ NtSetInformationProcess(IN HANDLE ProcessHandle,
 }
 
 /*
- * @unimplemented
+ * @implemented
  */
 NTSTATUS
 NTAPI
@@ -711,70 +1094,419 @@ NtSetInformationThread(IN HANDLE ThreadHandle,
                        IN ULONG ThreadInformationLength)
 {
     PETHREAD Thread;
+    ULONG Access;
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
-    NTSTATUS Status = STATUS_SUCCESS;
+    NTSTATUS Status;
+    HANDLE TokenHandle = NULL;
+    KPRIORITY Priority = 0;
+    KAFFINITY Affinity = 0, CombinedAffinity;
+    PVOID Address = NULL;
+    PEPROCESS Process;
+    ULONG DisableBoost = 0;
+    ULONG IdealProcessor = 0;
+    PTEB Teb;
+    ULONG TlsIndex = 0;
+    PVOID *ExpansionSlots;
+    PETHREAD ProcThread;
     PAGED_CODE();
 
-    DPRINT1("%s called for: %d\n", __FUNCTION__, ThreadInformationClass);
-    /* FIXME: This is REALLY wrong. Some types don't need THREAD_SET_INFORMATION */
-    /* FIXME: We should also check for certain things before doing the reference */
+    /* Verify Information Class validity */
+#if 0
+    Status = DefaultSetInfoBufferCheck(ThreadInformationClass,
+                                       PsThreadInfoClass,
+                                       RTL_NUMBER_OF(PsThreadInfoClass),
+                                       ThreadInformation,
+                                       ThreadInformationLength,
+                                       PreviousMode);
+    if (!NT_SUCCESS(Status)) return Status;
+#endif
+
+    /* Check what class this is */
+    Access = THREAD_SET_INFORMATION;
+    if (ThreadInformationClass == ThreadImpersonationToken)
+    {
+        /* Setting the impersonation token needs a special mask */
+        Access = THREAD_SET_THREAD_TOKEN;
+    }
+
+    /* Reference the process */
     Status = ObReferenceObjectByHandle(ThreadHandle,
-                                       THREAD_SET_INFORMATION,
+                                       Access,
                                        PsThreadType,
                                        PreviousMode,
                                        (PVOID*)&Thread,
                                        NULL);
-    if (NT_SUCCESS(Status))
-    {
-#if 0
-        switch (ThreadInformationClass)
-        {
-            case ThreadPriority:
+    if (!NT_SUCCESS(Status)) return Status;
+
+    /* Check what kind of information class this is */
+    switch (ThreadInformationClass)
+    {
+        /* Thread priority */
+        case ThreadPriority:
+
+            /* Check buffer length */
+            if (ThreadInformationLength != sizeof(KPRIORITY))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Get the priority */
+                Priority = *(PLONG)ThreadInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
 
-                if (u.Priority < LOW_PRIORITY || u.Priority >= MAXIMUM_PRIORITY)
+            /* Validate it */
+            if ((Priority > HIGH_PRIORITY) ||
+                (Priority <= LOW_PRIORITY))
+            {
+                /* Fail */
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+
+            /* Set the priority */
+            KeSetPriorityThread(&Thread->Tcb, Priority);
+            break;
+
+        case ThreadBasePriority:
+
+            /* Check buffer length */
+            if (ThreadInformationLength != sizeof(LONG))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Get the priority */
+                Priority = *(PLONG)ThreadInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Validate it */
+            if ((Priority > THREAD_BASE_PRIORITY_MAX) ||
+                (Priority < THREAD_BASE_PRIORITY_MIN))
+            {
+                /* These ones are OK */
+                if ((Priority != THREAD_BASE_PRIORITY_LOWRT + 1) &&
+                    (Priority != THREAD_BASE_PRIORITY_IDLE - 1))
                 {
-                    Status = STATUS_INVALID_PARAMETER;
-                    break;
+                    /* Check if the process is real time */
+                    if (PsGetCurrentProcess()->PriorityClass !=
+                        PROCESS_PRIORITY_CLASS_REALTIME)
+                    {
+                        /* It isn't, fail */
+                        Status = STATUS_INVALID_PARAMETER;
+                        break;
+                    }
                 }
-                KeSetPriorityThread(&Thread->Tcb, u.Priority);
+            }
+
+            /* Set the base priority */
+            KeSetBasePriorityThread(&Thread->Tcb, Priority);
+            break;
+
+        case ThreadAffinityMask:
+
+            /* Check buffer length */
+            if (ThreadInformationLength != sizeof(ULONG_PTR))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
                 break;
+            }
+
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Get the priority */
+                Affinity = *(PULONG_PTR)ThreadInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
 
-            case ThreadBasePriority:
-                KeSetBasePriorityThread (&Thread->Tcb, u.Increment);
+            /* Validate it */
+            if (!Affinity)
+            {
+                /* Fail */
+                Status = STATUS_INVALID_PARAMETER;
                 break;
+            }
 
-            case ThreadAffinityMask:
+            /* Get the process */
+            Process = Thread->ThreadsProcess;
 
-                /* Check if this is valid */
-                DPRINT1("%lx, %lx\n", Thread->ThreadsProcess->Pcb.Affinity, u.Affinity);
-                if ((Thread->ThreadsProcess->Pcb.Affinity & u.Affinity) !=
-                    u.Affinity)
+            /* Try to acquire rundown */
+            if (ExAcquireRundownProtection(&Process->RundownProtect))
+            {
+                /* Lock it */
+                KeEnterCriticalRegion();
+                ExAcquirePushLockShared(&Process->ProcessLock);
+
+                /* Combine masks */
+                CombinedAffinity = Affinity & Process->Pcb.Affinity;
+                if (CombinedAffinity != Affinity)
                 {
-                    DPRINT1("Wrong affinity given\n");
+                    /* Fail */
                     Status = STATUS_INVALID_PARAMETER;
                 }
                 else
                 {
-                    Status = KeSetAffinityThread(&Thread->Tcb, u.Affinity);
+                    /* Set the affinity */
+                    KeSetAffinityThread(&Thread->Tcb, CombinedAffinity);
                 }
+
+                /* Release the lock and rundown */
+                ExReleasePushLockShared(&Process->ProcessLock);
+                KeLeaveCriticalRegion();
+                ExReleaseRundownProtection(&Process->RundownProtect);
+            }
+            else
+            {
+                /* Too late */
+                Status = STATUS_PROCESS_IS_TERMINATING;
+            }
+
+            /* Return status */
+            break;
+
+        case ThreadImpersonationToken:
+
+            /* Check buffer length */
+            if (ThreadInformationLength != sizeof(HANDLE))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Save the token handle */
+                TokenHandle = *(PHANDLE)ThreadInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Assign the actual token */
+            Status = PsAssignImpersonationToken(Thread, TokenHandle);
+            break;
+
+        case ThreadQuerySetWin32StartAddress:
+
+            /* Check buffer length */
+            if (ThreadInformationLength != sizeof(ULONG_PTR))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
                 break;
+            }
 
-            case ThreadImpersonationToken:
-                Status = PsAssignImpersonationToken (Thread, u.Handle);
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Get the priority */
+                Address = *(PVOID*)ThreadInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Set the address */
+            Thread->Win32StartAddress = Address;
+            break;
+
+        case ThreadIdealProcessor:
+
+            /* Check buffer length */
+            if (ThreadInformationLength != sizeof(ULONG_PTR))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
                 break;
+            }
 
-            case ThreadQuerySetWin32StartAddress:
-                Thread->Win32StartAddress = u.Address;
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Get the priority */
+                IdealProcessor = *(PULONG_PTR)ThreadInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Validate it */
+            if (IdealProcessor > MAXIMUM_PROCESSORS)
+            {
+                /* Fail */
+                Status = STATUS_INVALID_PARAMETER;
                 break;
+            }
 
-            default:
-                /* Shoult never occure if the data table is correct */
-                KEBUGCHECK(0);
-        }
-#endif
-        ObDereferenceObject (Thread);
+            /* Set the ideal */
+            Status = KeSetIdealProcessorThread(&Thread->Tcb,
+                                               (CCHAR)IdealProcessor);
+
+            /* Get the TEB and protect the thread */
+            Teb = Thread->Tcb.Teb;
+            if ((Teb) && (ExAcquireRundownProtection(&Thread->RundownProtect)))
+            {
+                /* Save the ideal processor */
+                Teb->IdealProcessor = Thread->Tcb.IdealProcessor;
+
+                /* Release rundown protection */
+                ExReleaseRundownProtection(&Thread->RundownProtect);
+            }
+
+            break;
+
+        case ThreadPriorityBoost:
+
+            /* Check buffer length */
+            if (ThreadInformationLength != sizeof(ULONG_PTR))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Get the priority */
+                DisableBoost = *(PULONG_PTR)ThreadInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* Call the kernel */
+            KeSetDisableBoostThread(&Thread->Tcb, (BOOLEAN)DisableBoost);
+            break;
+
+        case ThreadZeroTlsCell:
+
+            /* Check buffer length */
+            if (ThreadInformationLength != sizeof(ULONG_PTR))
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+
+            /* Use SEH for capture */
+            _SEH2_TRY
+            {
+                /* Get the priority */
+                TlsIndex = *(PULONG_PTR)ThreadInformation;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get the exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            if (!NT_SUCCESS(Status)) break;
+
+            /* This is only valid for the current thread */
+            if (Thread != PsGetCurrentThread())
+            {
+                /* Fail */
+                Status = STATUS_INVALID_PARAMETER;
+                break;
+            }
+
+            /* Get the process */
+            Process = Thread->ThreadsProcess;
+
+            /* Loop the threads */
+            ProcThread = PsGetNextProcessThread(Process, NULL);
+            while (ProcThread)
+            {
+                /* Acquire rundown */
+                if (ExAcquireRundownProtection(&ProcThread->RundownProtect))
+                {
+                    /* Get the TEB */
+                    Teb = ProcThread->Tcb.Teb;
+                    if (Teb)
+                    {
+                        /* Check if we're in the expansion range */
+                        if (TlsIndex > TLS_MINIMUM_AVAILABLE - 1)
+                        {
+                            if (TlsIndex < (TLS_MINIMUM_AVAILABLE +
+                                            TLS_EXPANSION_SLOTS) - 1)
+                            {
+                                /* Check if we have expansion slots */
+                                ExpansionSlots = Teb->TlsExpansionSlots;
+                                if (ExpansionSlots)
+                                {
+                                    /* Clear the index */
+                                    ExpansionSlots[TlsIndex - TLS_MINIMUM_AVAILABLE] = 0;
+                                }
+                            }
+                        }
+                        else
+                        {
+                            /* Clear the index */
+                            Teb->TlsSlots[TlsIndex] = NULL;
+                        }
+                    }
+
+                    /* Release rundown */
+                    ExReleaseRundownProtection(&ProcThread->RundownProtect);
+                }
+
+                /* Go to the next thread */
+                ProcThread = PsGetNextProcessThread(Process, ProcThread);
+            }
+
+            /* All done */
+            break;
+
+        default:
+            /* We don't implement it yet */
+            DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
+            Status = STATUS_NOT_IMPLEMENTED;
     }
 
+    /* Dereference and return status */
+    ObDereferenceObject(Thread);
     return Status;
 }
 
@@ -792,80 +1524,268 @@ NtQueryInformationThread(IN HANDLE ThreadHandle,
     PETHREAD Thread;
     KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
     NTSTATUS Status = STATUS_SUCCESS;
+    ULONG Access;
+    ULONG Length = 0;
+    PTHREAD_BASIC_INFORMATION ThreadBasicInfo =
+        (PTHREAD_BASIC_INFORMATION)ThreadInformation;
+    PKERNEL_USER_TIMES ThreadTime = (PKERNEL_USER_TIMES)ThreadInformation;
+    KIRQL OldIrql;
     PAGED_CODE();
 
-    DPRINT1("%s called for: %d\n", __FUNCTION__, ThreadInformationClass);
+    if (PreviousMode != KernelMode)
+    {
+        _SEH2_TRY
+        {
+            ProbeForWrite(ThreadInformation,
+                          ThreadInformationLength,
+                          sizeof(ULONG));
+
+            if (ReturnLength)
+            {
+                ProbeForWriteUlong(ReturnLength);
+            }
+        }
+        _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+        {
+            Status = _SEH2_GetExceptionCode();
+        }
+        _SEH2_END;
+
+        if (!NT_SUCCESS(Status)) return Status;
+    }
+
+    /* Check what class this is */
+    Access = THREAD_QUERY_INFORMATION;
+
+    /* Reference the process */
     Status = ObReferenceObjectByHandle(ThreadHandle,
-                                       THREAD_QUERY_INFORMATION,
+                                       Access,
                                        PsThreadType,
                                        PreviousMode,
                                        (PVOID*)&Thread,
                                        NULL);
     if (!NT_SUCCESS(Status)) return Status;
 
-#if 0
+    /* Check what kind of information class this is */
     switch (ThreadInformationClass)
     {
+        /* Basic thread information */
         case ThreadBasicInformation:
-            /* A test on W2K agains ntdll shows NtQueryInformationThread return STATUS_PENDING
-            * as ExitStatus for current/running thread, while KETHREAD's ExitStatus is
-            * 0. So do the conversion here:
-            * -Gunnar     */
-            u.TBI.ExitStatus = (Thread->ExitStatus == 0) ? STATUS_PENDING : Thread->ExitStatus;
-            u.TBI.TebBaseAddress = (PVOID)Thread->Tcb.Teb;
-            u.TBI.ClientId = Thread->Cid;
-            u.TBI.AffinityMask = Thread->Tcb.Affinity;
-            u.TBI.Priority = Thread->Tcb.Priority;
-            u.TBI.BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
+
+            /* Set return length */
+            Length = sizeof(THREAD_BASIC_INFORMATION);
+
+            if (ThreadInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+            /* Protect writes with SEH */
+            _SEH2_TRY
+            {
+                /* Write all the information from the ETHREAD/KTHREAD */
+                ThreadBasicInfo->ExitStatus = Thread->ExitStatus;
+                ThreadBasicInfo->TebBaseAddress = (PVOID)Thread->Tcb.Teb;
+                ThreadBasicInfo->ClientId = Thread->Cid;
+                ThreadBasicInfo->AffinityMask = Thread->Tcb.Affinity;
+                ThreadBasicInfo->Priority = Thread->Tcb.Priority;
+                ThreadBasicInfo->BasePriority = KeQueryBasePriorityThread(&Thread->Tcb);
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
             break;
 
+        /* Thread time information */
         case ThreadTimes:
-            u.TTI.KernelTime.QuadPart = Thread->Tcb.KernelTime * 100000LL;
-            u.TTI.UserTime.QuadPart = Thread->Tcb.UserTime * 100000LL;
-            u.TTI.CreateTime = Thread->CreateTime;
-            /*This works*/
-            u.TTI.ExitTime = Thread->ExitTime;
+
+            /* Set the return length */
+            Length = sizeof(KERNEL_USER_TIMES);
+
+            if (ThreadInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+            /* Protect writes with SEH */
+            _SEH2_TRY
+            {
+                /* Copy time information from ETHREAD/KTHREAD */
+                ThreadTime->KernelTime.QuadPart = Thread->Tcb.KernelTime *
+                                                   100000LL;
+                ThreadTime->UserTime.QuadPart = Thread->Tcb.UserTime *
+                                                 100000LL;
+                ThreadTime->CreateTime = Thread->CreateTime;
+                ThreadTime->ExitTime = Thread->ExitTime;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
             break;
 
         case ThreadQuerySetWin32StartAddress:
-            u.Address = Thread->Win32StartAddress;
+
+            /* Set the return length*/
+            Length = sizeof(PVOID);
+
+            if (ThreadInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+            /* Protect write with SEH */
+            _SEH2_TRY
+            {
+                /* Return the Win32 Start Address */
+                *(PVOID*)ThreadInformation = Thread->Win32StartAddress;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
             break;
 
         case ThreadPerformanceCount:
-            /* Nebbett says this class is always zero */
-            u.Count.QuadPart = 0;
+
+            /* Set the return length*/
+            Length = sizeof(LARGE_INTEGER);
+
+            if (ThreadInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+            /* Protect write with SEH */
+            _SEH2_TRY
+            {
+                /* FIXME */
+                (*(PLARGE_INTEGER)ThreadInformation).QuadPart = 0;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
             break;
 
         case ThreadAmILastThread:
-            if (Thread->ThreadsProcess->ThreadListHead.Flink->Flink ==
-                &Thread->ThreadsProcess->ThreadListHead)
+
+            /* Set the return length*/
+            Length = sizeof(ULONG);
+
+            if (ThreadInformationLength != Length)
             {
-                u.Last = TRUE;
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
             }
-            else
+            /* Protect write with SEH */
+            _SEH2_TRY
             {
-                u.Last = FALSE;
+                /* Return whether or not we are the last thread */
+                *(PULONG)ThreadInformation = ((Thread->ThreadsProcess->
+                                               ThreadListHead.Flink->Flink ==
+                                               &Thread->ThreadsProcess->
+                                               ThreadListHead) ?
+                                              TRUE : FALSE);
             }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
             break;
 
         case ThreadIsIoPending:
+
+            /* Set the return length*/
+            Length = sizeof(ULONG);
+
+            if (ThreadInformationLength != Length)
             {
-                KIRQL OldIrql;
+                Status = STATUS_INFO_LENGTH_MISMATCH;
+                break;
+            }
+            /* Raise the IRQL to protect the IRP list */
+            KeRaiseIrql(APC_LEVEL, &OldIrql);
 
-                /* Raise the IRQL to protect the IRP list */
-                KeRaiseIrql(APC_LEVEL, &OldIrql);
-                u.IsIoPending = !IsListEmpty(&Thread->IrpList);
-                KeLowerIrql(OldIrql);
+            /* Protect write with SEH */
+            _SEH2_TRY
+            {
+                /* Check if the IRP list is empty or not */
+                *(PULONG)ThreadInformation = !IsListEmpty(&Thread->IrpList);
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                /* Get exception code */
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+
+            /* Lower IRQL back */
+            KeLowerIrql(OldIrql);
+            break;
+
+        case ThreadDescriptorTableEntry:
+            DPRINT1("NtQueryInformationThread(): case ThreadDescriptorTableEntry not implemented!\n");
+            Status = STATUS_NOT_IMPLEMENTED;
+            break;
+
+        case ThreadPriorityBoost:
+
+            /* Set the return length*/
+            Length = sizeof(ULONG);
+
+            if (ThreadInformationLength != Length)
+            {
+                Status = STATUS_INFO_LENGTH_MISMATCH;
                 break;
             }
 
+            _SEH2_TRY
+            {
+                *(PULONG)ThreadInformation = Thread->Tcb.DisableBoost ? 1 : 0;
+            }
+            _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+            {
+                Status = _SEH2_GetExceptionCode();
+            }
+            _SEH2_END;
+            break;
+
+        /* Anything else */
         default:
-            /* Shoult never occure if the data table is correct */
-            KEBUGCHECK(0);
+
+            /* Not yet implemented */
+            DPRINT1("Not implemented: %lx\n", ThreadInformationClass);
+            Status = STATUS_NOT_IMPLEMENTED;
     }
-#endif
+
+    /* Protect write with SEH */
+    _SEH2_TRY
+    {
+        /* Check if caller wanted return length */
+        if (ReturnLength) *ReturnLength = Length;
+    }
+    _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
+    {
+        /* Get exception code */
+        Status = _SEH2_GetExceptionCode();
+    }
+    _SEH2_END;
+
+    /* Dereference the thread, and return */
     ObDereferenceObject(Thread);
-    return(Status);
+    return Status;
 }
 
 /* EOF */