
/**
 * @file: services.c
 *
 * Tento soubor tvori mustek mezi frameworkem na praci s objekty exekutivy
 * a rutinou obsluhujici pozadavky na ovladac objview.sys. Jedna se o
 * analogii k systemovym volanim (NtXXX rutiny v hlavnim modulu jadra).
 * S objekty exekutivy pracuje pres vlastni system handle. Jednotliva
 * handle preklada na adresy tel objektu exekutivy a provadi s nimi
 * prislusne operace. Jedna se o cteni stavu techto objektu.
 */
#include <ntddk.h>
#include "driver.h"
#include "utils.h"
#include "object_header.h"
#include "object_initializer.h"
#include "object_type.h"
#include "object_directory.h"
#include "object.h"
#include "handles.h"
#include "services.h"



/** Vytvori handle k zadanemu objektu.
 *
 * @param InBuffer Informace o cilovem objektu. Presneji, jedna se o
 * jeho plne jmeno.
 * @param InBufferLengt. Velikost bufferu s informacemi o cilovem objektu.
 * @param OutBuffer Do tohoto bufferu rutina zapise handle objektu, pokud
 * se jej podari vytvorit.
 *
 * @return Rutina vraci kod NTSTATUS indikujici uspech operace.
 */
NTSTATUS OpenObjectService(POBJVIEW_OPEN_IN InBuffer, ULONG32 InBufferLength, POBJVIEW_OPEN_OUT OutBuffer)
{
  PWCHAR Name = NULL;
  PWCHAR KernelName = NULL;
  UNICODE_STRING uName;
  ULONG32 KernelNameLength = 0;
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("services.c: OpenObjectService(InBuffer=0x%p; InBufferLength=%u; OutBuffer=0x%p)\n", InBuffer, InBufferLength, OutBuffer));

  if (InBuffer->ObjectNameLength <= InBufferLength - sizeof(ULONG32)) {
    Name = (PWCHAR)&InBuffer->ObjectName;
    KernelNameLength = (InBuffer->ObjectNameLength + 1) * sizeof(WCHAR);
    KernelName = ExAllocatePoolWithTag(NonPagedPool, KernelNameLength, POOL_TAG);
    if (KernelName != NULL) {
      RtlZeroMemory(KernelName, KernelNameLength);
      RtlCopyMemory(KernelName, Name, KernelNameLength - sizeof(WCHAR));
      RtlInitUnicodeString(&uName, KernelName);
      Status = HandleCreate(&uName, &OutBuffer->Handle);
      ExFreePoolWithTag(KernelName, POOL_TAG);
    } else Status = STATUS_INSUFFICIENT_RESOURCES;
  } else Status = STATUS_BUFFER_TOO_SMALL;

  KdPrint(("services.c: OpenObjectService(-):0x%x\n", Status));
  return Status;
}


/** Zrusi zadane handle k objektu exekutivy.
 *
 * @param InBuffer Adresa bufferu, ktery obsahuje handle, jenz chce
 * volajici zrusit.
 *
 * @return Funkce vraci kod NTSTATUS indikujici uspech operace.
 */
NTSTATUS CloseObjectService(POBJVIEW_CLOSE_IN Buffer)
{
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("services.c: CloseObjectService(Buffer=0x%p)\n", Buffer));

  Status = HandleClose(Buffer->Handle);

  KdPrint(("services.c: CloseObjectService(-):0x%x\n", Status));
  return Status;
}


/** Vrati informace o hlavicce zadaneho objektu exekutivy.
 *
 * @param InBuffer Adresa promenne obsahujici handle ciloveho objektu.
 * @param OutBuffer OutBuffer Adresa bufferu, kam funkce v pripade uspechu
 * zapise udaje z hlavicky ciloveho objektu.
 *
 * @return Funkce vraci hodnotu NTSTATUS indikujici uspech ci neuspech operace.
 */
NTSTATUS GetObjectHeaderService(POBJVIEW_GET_HEADER_IN InBuffer, POBJVIEW_GET_HEADER_OUT OutBuffer)
{
  PVOID Object;
  OBJECT_HEADER_INFO ObjectHeaderInfo;
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("services.c: GetObjectHeaderService(InBuffer=0x%p; OutBuffer)\n", InBuffer, OutBuffer));

  Status = HandleTranslate(InBuffer->Handle, &Object);
  if (NT_SUCCESS(Status)) {
    Status = OBGetObjectHeaderInfo(Object, &ObjectHeaderInfo);
    if (NT_SUCCESS(Status)) {
      RtlZeroMemory(OutBuffer, sizeof(OBJVIEW_GET_HEADER_OUT));
      OutBuffer->InfoMask = ObjectHeaderInfo.InfoMask;
      OutBuffer->CreatorInfoOffset = ObjectHeaderInfo.CreatorInfoOffset;
      OutBuffer->Flags = ObjectHeaderInfo.Flags;
      OutBuffer->HandleCount = ObjectHeaderInfo.HandleCount;
      OutBuffer->HandleInfoOffset = ObjectHeaderInfo.HandleInfoOffset;
      OutBuffer->NameInfoOffset = ObjectHeaderInfo.NameInfoOffset;
      OutBuffer->PointerCount = ObjectHeaderInfo.PointerCount;
      OutBuffer->QuotaInfoOffset = ObjectHeaderInfo.QuotaInfoOffset;
      OutBuffer->ProcessInfoOffset = ObjectHeaderInfo.ProcessInfoOffset;
      OutBuffer->ExclusiveProcessId = 0;
	  if (ObjectHeaderInfo.ExclusiveProcess != NULL)
        OutBuffer->ExclusiveProcessId = GetProcessId(ObjectHeaderInfo.ExclusiveProcess);

      OutBuffer->CreatorProcessId = ObjectHeaderInfo.CreatorUniqueProcessId;
      if (ObjectHeaderInfo.Name.Buffer != NULL)
        ExFreePoolWithTag(ObjectHeaderInfo.Name.Buffer, POOL_TAG);
    }
  }

  KdPrint(("services.c: GetObjectHeaderService(-):0x%x\n", Status));
  return Status;
}


/** Zjisti informace o jmene objektu.
 *
 * @param InBuffer Buffer obsahujici handle ciloveho objektu.
 * @param OutBuffer Adresa bufferu, ktery funkce v pripade uspechu naplni
 * jmenem ciloveho objektu exekutivy.
 * @param OutBufferLength Na vstupu tento parametr odkazuje na velikost
 * bufferu v parametru OutBuffer. Na vystupu funkce tuto hodnotu prepise na
 * pocet bajtu zapsanych do bufferu OutBuffer.
 *
 * @return Funkce vraci hodnotu NTSTATUS indikujici uspech ci neuspech
 * operace.
 */
NTSTATUS GetObjectNameInfoService(POBJVIEW_GET_NAME_INFO_IN InBuffer, POBJVIEW_GET_NAME_INFO_OUT OutBuffer, PULONG32 OutBufferLength)
{
  ULONG LastElementLength = 0;
  PVOID Object;
  UNICODE_STRING FullName;
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("services.c: GetObjectNameInfoService(InBuffer=0x%p; OutBuffer=0x%p; *OutBufferLength=0x%p)\n", InBuffer, OutBuffer, *OutBufferLength));

  Status = HandleTranslate(InBuffer->Handle, &Object);
  if (NT_SUCCESS(Status)) {
    Status = OBGetFullName(Object, &FullName, &LastElementLength);
    if (NT_SUCCESS(Status)) {
      if (*OutBufferLength >= FullName.Length + sizeof(OBJVIEW_GET_NAME_INFO_OUT) - sizeof(WCHAR)) {
        OutBuffer->NameLength = FullName.Length;
        OutBuffer->NameOffset = (FullName.Length - LastElementLength) / sizeof(WCHAR);
        RtlCopyMemory(&OutBuffer->FullName, FullName.Buffer, FullName.Length);
      } else Status = STATUS_BUFFER_TOO_SMALL;

      *OutBufferLength = FullName.Length + sizeof(OBJVIEW_GET_NAME_INFO_OUT) - sizeof(WCHAR);
 
      if (FullName.Buffer != NULL)
        ExFreePoolWithTag(FullName.Buffer, POOL_TAG);
    }
  }

  KdPrint(("services.c: GetObjectNameInfoService(-):0x%x\n", Status));
  return Status;
}


/** Zjisti informace o objekty tykajici se toho, jak moc ubira kvotu
 *  procesu za kazde existujici handle.
 *
 *  @param InBuffer Buffer obsahujici handle ciloveho objektu.
 *  @param OutBuffer Adresa bufferu, tak funkce v pripade uspechu zapise
 *  informace o narokach na kvotu pro dany proces.
 *
 *  @return Funkce vraci hodnotu NTSTATUS indikujici upsech ci neuspech
 *  operace.
 */
NTSTATUS GetObjectQuotaInfoService(POBJVIEW_GET_QUOTA_INFO_IN InBuffer, POBJVIEW_GET_QUOTA_INFO_OUT OutBuffer)
{
  PVOID Object = NULL;
  PEPROCESS ExclusiveProcess = NULL;
  OBJECT_HEADER_INFO ObjectHeaderInfo;
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("services.c: GetObjectQuotaInfoService(InBuffer=0x%p; OutBuffer=0x%p)\n", InBuffer, OutBuffer));

  Status = HandleTranslate(InBuffer->Handle, &Object);
  if (NT_SUCCESS(Status)) {
    Status = OBGetObjectHeaderInfo(Object, &ObjectHeaderInfo);
    if (NT_SUCCESS(Status)) {
      if (ObjectHeaderInfo.QuotaInfoOffset != 0) {
        OutBuffer->NonPagedPoolCharge = ObjectHeaderInfo.NonPagedPoolCharge;
        OutBuffer->PagedPoolCharge = ObjectHeaderInfo.PagedPoolCharge;
        OutBuffer->SecurityDescriptorCharge = ObjectHeaderInfo.SecurityDescriptorCharge;
        ExclusiveProcess = ObjectHeaderInfo.ExclusiveProcess;
        if (ExclusiveProcess != NULL)
          OutBuffer->ExclusiveProcessId = GetProcessId(ExclusiveProcess);
      } else Status = STATUS_NOT_FOUND;

      if (ObjectHeaderInfo.Name.Buffer != NULL)
        ExFreePoolWithTag(ObjectHeaderInfo.Name.Buffer, POOL_TAG);
    }
  }

  KdPrint(("services.c: GetObjectQuotaInfoService(-):0x%x\n", Status));
  return Status;
}


/** Rutina vraci informace o procesu, ktery je tvurcem ciloveho objektu.
 *
 *  @param InBuffer Adresa bufferu s handle na cilovy objekt.
 *  @param OutBuffer Adresa promenne, ktam rutina v pripade uspechu zapise
 *  PID procesu, ktery je tvurcem ciloveho objektu.
 *
 *  @return Rutina vraci kod NTSTATUS indikujici uspech ci neuspech operace.
 *  Navic vraci STATUS_NOT_FOUND v pripade, ze dany objekt nedisponuje informacemi
 *  o svem tvurci.
 */
NTSTATUS GetObjectCreatorInfoService(POBJVIEW_GET_CREATOR_INFO_IN InBuffer, POBJVIEW_GET_CREATOR_INFO_OUT OutBuffer)
{
  PVOID Object = NULL;
  OBJECT_HEADER_INFO ObjectHeaderInfo;
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("services.c: GetObjectCreatorInfoService(InBuffer=0x%p; OutBuffer=0x%p)\n", InBuffer, OutBuffer));

  Status = HandleTranslate(InBuffer->Handle, &Object);
  if (NT_SUCCESS(Status)) {
    Status = OBGetObjectHeaderInfo(Object, &ObjectHeaderInfo);
	if (NT_SUCCESS(Status)) {
      if (ObjectHeaderInfo.CreatorInfoOffset != 0) {
        OutBuffer->CreatorProcessId = ObjectHeaderInfo.CreatorUniqueProcessId;
      } else Status = STATUS_NOT_FOUND;

	  if (ObjectHeaderInfo.Name.Buffer != NULL)
        ExFreePoolWithTag(ObjectHeaderInfo.Name.Buffer, POOL_TAG);
    }
  }

  KdPrint(("services.c: GetObjectCreatorInfoService(-):0x%x\n", Status));
  return Status;
}


/** Vraci informace o typu daneho objektu.
 *
 * @param InBuffer Buffer obsahujici handle k cilovemu objektu.
 * @param OutBuffer Adresa bloku pameti, ktery funkce v pripade uspechu
 * vyplni informacemi o typu ciloveho objektu. 
 * @param OutBufferLength Na vstupu tento parametr obsahuje adresu promenne
 * udavajici velikost bloku pameti predaneho parametrem Outbuffer. Na vystupu
 * obsahuje bud pocet zapsanych bajtu (vejdou-li se do bufferu), nebo minimalni
 * nutnou velikost bufferu OutBuffer, aby se tam vsechna data o typu ciloveho
 * objektu vesla.
 *
 * @return Funkce vraci kod NTSTATUS indikujici uspech ci neuspech operace.
 * V pripade, ze je buffer OutBuffer prilis maly, aby pojal vsechny informace,
 * rutina vrati STATUS_BUFFER_TOO_SMALL.
 */
NTSTATUS GetObjectTypeInfoService(POBJVIEW_GET_TYPE_INFO_IN InBuffer, POBJVIEW_GET_TYPE_INFO_OUT OutBuffer, PULONG32 OutBufferLength)
{
  PWCHAR Tmp = NULL;
  PVOID Object = NULL;
  OBJECT_TYPE_INFO TypeInfo;
  POBJECT_TYPE ObjectType = NULL;
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("services.c: GetObjectTypeInfoService(InBuffer=0x%p; OutBuffer=0x%p; *OutBufferLength=%u)\n", InBuffer, OutBuffer, *OutBufferLength));

  Status = HandleTranslate(InBuffer->Handle, &Object);
  if (NT_SUCCESS(Status)) {
    ObjectType = OBGetObjectType(Object);
	if (ObjectType != NULL) {
      Status = OTGetSpecificInfo(ObjectType, &TypeInfo);
      if (NT_SUCCESS(Status)) {
        if (OutBuffer->NameLength - sizeof(WCHAR) + sizeof(OBJVIEW_GET_TYPE_INFO_OUT) <= *OutBufferLength) {
          OutBuffer->DefaultObject = TypeInfo.DefaultObject;
          OutBuffer->Index = TypeInfo.Index;
          OutBuffer->Key = TypeInfo.Key;
          OutBuffer->TpyeStatistics = TypeInfo.Statistics;
          OutBuffer->InitializerFlags = TypeInfo.InitializerFlags;
          OutBuffer->InitializerMethods = TypeInfo.InitializerMethods;
          OutBuffer->InitializerOtherInfo = TypeInfo.InitializerOtherInfo;
          OutBuffer->NameLength = TypeInfo.Name.Length;
          if (OutBuffer->NameLength > 0)
            RtlCopyMemory(&OutBuffer->Name, TypeInfo.Name.Buffer, OutBuffer->NameLength);
	    } else Status = STATUS_BUFFER_TOO_SMALL;

        *OutBufferLength = sizeof(OBJVIEW_GET_TYPE_INFO_OUT) + OutBuffer->NameLength - sizeof(WCHAR);
        if (TypeInfo.Name.Buffer != NULL)
          ExFreePoolWithTag(TypeInfo.Name.Buffer, POOL_TAG);
      }

      OBReleaseObjectPointer(ObjectType);
    } else Status = STATUS_UNSUCCESSFUL;
  }

  KdPrint(("services.c: GetObjectTypeInfoService(-):0x%x, *OutBufferLength\n", Status, *OutBufferLength));
  return Status;
}


/** Vrati databazi handle daneho objektu.
 *
 * @param InBuffer Adresa bufferu obsahujiciho handle k cilovemu objektu.
 * @param Outbuffer Adresa bufferu, kam funkce v pripade uspechu zapise
 * databazi handle ciloveho objektu.
 * @param OutBufferLength Na vstupu tento parametr odkazuje na promennou, ktera
 * udava velikost bloku pameti predaneho v parametru OutBuffer. Na vystupu funkce
 * tuto promennou naplni bud poctem bajtu zapsanych do bufferu OutBuffer, nebo
 * minimalni velikosti, kterou tento buffer musi disponovat, aby se do nej data
 * o databazi handle vesla.
 *
 * @return Funkce vraci hodnotu NTSTATUS indikujici uspech ci neeuspech operace.
 * V pripade, ze buffer OutBuffer je prilis maly, takze se do nej data o databazi
 * handle nevejdou, funkce vrati STATUS_BUFFER_TOO_SMALL.
 */
NTSTATUS GetObjectHandleInfoService(POBJVIEW_GET_HANDLE_INFO_IN InBuffer, POBJVIEW_GET_HANDLE_INFO_OUT OutBuffer, PULONG32 OutBufferLength)
{
  LONG i = 0;
  ULONG32 RequiredLength = 0;
  PVOID Object = NULL;
  ULONG32 ObjectFlags = 0;
  PVOID ObjectHeader = NULL;
  POBJECT_HANDLE_COUNT_DATABASE Database = NULL;
  POBJECT_HEADER_HANDLE_INFO HandleInfo = NULL;
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("services.c: GetObjectHandleInfoService(InBuffer=0x%p; OutBuffer=0x%p; *OutBufferLength=%u)\n", InBuffer, OutBuffer, *OutBufferLength));

  Status = HandleTranslate(InBuffer->Handle, &Object);
  if (NT_SUCCESS(Status)) {
    ObjectHeader = OHGetObjectHeader(Object);
	if (ObjectHeader != NULL) {
      ObjectFlags = OHGetFlags(ObjectHeader);
	  HandleInfo = (POBJECT_HEADER_HANDLE_INFO)OHGetInfoHeader(ObjectHeader, OH_HEADER_HANDLE_INFO);
	  if (HandleInfo != NULL) {
        if ((ObjectFlags & OB_FLAG_SINGLE_HANDLE_ENTRY) == 0) {
          Database = HandleInfo->HandleCountDataBase;
		  RequiredLength = sizeof(OBJVIEW_GET_HANDLE_INFO_OUT) + (Database->CountEntries - 1) * 2 * sizeof(ULONG_PTR);
        } else RequiredLength = sizeof(OBJVIEW_GET_HANDLE_INFO_OUT);

		if (*OutBufferLength >= RequiredLength) {
          *OutBufferLength = RequiredLength;
		  if (Database != NULL) {
		    OutBuffer->Count = Database->CountEntries;
			for (i = 0; i < (LONG)OutBuffer->Count; ++i) {
              OutBuffer->Entries[i].HandleCount = Database->HandleCountEntries[i].Entry.HandleCount;
			  if (Database->HandleCountEntries[i].Process != NULL)
			    OutBuffer->Entries[i].ProcessId = GetProcessId(Database->HandleCountEntries[i].Process);
			  else OutBuffer->Entries[i].ProcessId = 0;
			}
		  } else {
            OutBuffer->Count = 1;
			OutBuffer->Entries[0].HandleCount = HandleInfo->SingleEntry.Entry.HandleCount;
			if (HandleInfo->SingleEntry.Process != NULL)
              OutBuffer->Entries[0].ProcessId = GetProcessId(HandleInfo->SingleEntry.Process);
			else OutBuffer->Entries[0].ProcessId = 0;
          }
		} else {
          Status = STATUS_BUFFER_TOO_SMALL;
          *OutBufferLength = RequiredLength;
        }
	  } else Status = STATUS_NOT_FOUND;
	} else Status = STATUS_UNSUCCESSFUL;
  }

  KdPrint(("services.c: GetObjectHandleInfoService(-):0x%x, *OutBufferLength\n", Status, *OutBufferLength));
  return Status;
}


/** Vrati data z tela ciloveho objektu. Struktura techto dat zavisi na
 *  typu daneho objektu.
 *
 *  @param InBuffer Buffer obsahujici handle ciloveho objektu.
 *  @param OutBuffer Adresa bloku pameti, kam funkce v pripade uspechu yapise
 *  data o cilovem objektu.
 *  @param OutBufferLength Na vstupu tento paramtr obsahuje adresu promenne
 *  udavajici velikost bloku OutBUffer. Na vystupu tuto hodnotu funkce nastavi
 *  bud na pocet bajtu zapsanych do bufferu OutBuffer, nebo na minimalni velikost,
 *  kterou musi tento buffer mit, aby se do nej prislusna data vesla.
 *
 *  @return Funkce vraci hodnotu NTSTATUS indikujici uspech ci neuspech
 *  operace. V pripade, ze je buffer OutBuffer prilis maly, takze se do neho
 *  data o cilovem objektu nevedjou, rutina vrati STATUS_BUFFER_TOO_SMALL.
 */
NTSTATUS GetObjectSpecificInfoService(POBJVIEW_GET_SPECIFIC_INFO_IN InBuffer, PVOID OutBuffer, PULONG32 OutBufferLength)
{
  ULONG32 InfoLength = 0;
  PWCHAR DirInfo = NULL;
  PVOID Object = NULL;
  POBJECT_TYPE ObjectType;
  PUNICODE_STRING ObjectTypeName = NULL;
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  POBJVIEW_GET_TYPE_INFO_OUT TypeSpecificInfoOut = NULL;
  OBJECT_TYPE_INFO ObjectTypeInfo;
  PKMUTANT MutantObject = NULL;
  PKEVENT EventObject = NULL;
  PKSEMAPHORE SemaphoreObject = NULL;
  PEVENT_SPECIFIC_INFO_OUT EventSpecificInfoOut = NULL;
  PSEMAPHORE_SPECIFIC_INFO_OUT SemaphoreSpecificInfoOut = NULL;
  PMUTANT_SPECIFIC_INFO_OUT MutantSpecificInfoOut = NULL;
  KdPrint(("services.c: GetObjectSpecificInfoService(InBuffer=0x%p; OutBuffer=0x%p; *OutBufferLength=%u)\n", InBuffer, OutBuffer, *OutBufferLength));

  Status = HandleTranslate(InBuffer->Handle, &Object);
  if (NT_SUCCESS(Status)) {
    ObjectType = OBGetObjectType(Object);
    if (ObjectType != NULL) {
      ObjectTypeName = OTGetName(ObjectType);
	  if (wcsncmp(ObjectTypeName->Buffer, L"Directory", wcslen(L"Directory")) == 0) {
        Status = DOGetDirectoryInfo(Object, &DirInfo, &InfoLength);
        if (NT_SUCCESS(Status)) {
	      if (*OutBufferLength >= InfoLength + sizeof(WCHAR)) {
            RtlZeroMemory(OutBuffer, InfoLength + sizeof(WCHAR));
            RtlCopyMemory(OutBuffer, DirInfo, InfoLength);
          } else Status = STATUS_BUFFER_TOO_SMALL;

          *OutBufferLength = InfoLength + sizeof(WCHAR);
		  if (DirInfo != NULL)
            ExFreePoolWithTag(DirInfo, POOL_TAG);
	    }
	  } else if (wcsncmp(ObjectTypeName->Buffer, L"Type", wcslen(L"Type")) == 0) {
        Status = OTGetSpecificInfo((POBJECT_TYPE)Object, &ObjectTypeInfo);
        if (NT_SUCCESS(Status)) {
          TypeSpecificInfoOut = OutBuffer;
		  if (*OutBufferLength >= sizeof(OBJVIEW_GET_TYPE_INFO_OUT) + ObjectTypeInfo.Name.Length * sizeof(WCHAR)) {
            TypeSpecificInfoOut->DefaultObject = ObjectTypeInfo.DefaultObject;
			TypeSpecificInfoOut->Index = ObjectTypeInfo.Index;
			TypeSpecificInfoOut->InitializerFlags = ObjectTypeInfo.InitializerFlags;
			TypeSpecificInfoOut->InitializerMethods = ObjectTypeInfo.InitializerMethods;
			TypeSpecificInfoOut->InitializerOtherInfo = ObjectTypeInfo.InitializerOtherInfo;
			TypeSpecificInfoOut->Key = ObjectTypeInfo.Key;
			TypeSpecificInfoOut->TpyeStatistics = ObjectTypeInfo.Statistics;
			TypeSpecificInfoOut->NameLength = ObjectTypeInfo.Name.Length;
			RtlCopyMemory(TypeSpecificInfoOut->Name, ObjectTypeInfo.Name.Buffer, TypeSpecificInfoOut->NameLength);
          } else Status = STATUS_BUFFER_TOO_SMALL;

          *OutBufferLength = sizeof(OBJVIEW_GET_TYPE_INFO_OUT) + TypeSpecificInfoOut->NameLength * sizeof(WCHAR);
		  if (ObjectTypeInfo.Name.Buffer != NULL)
            ExFreePoolWithTag(ObjectTypeInfo.Name.Buffer, POOL_TAG);
		}
      } else if (wcsncmp(ObjectTypeName->Buffer, L"Event", wcslen(L"Event")) == 0) {
        if (*OutBufferLength >= sizeof(EVENT_SPECIFIC_INFO_OUT)) {
          EventObject = (PKEVENT)Object;
          EventSpecificInfoOut = (PEVENT_SPECIFIC_INFO_OUT)OutBuffer;
		  EventSpecificInfoOut->EventType = EventObject->Header.Type;
          EventSpecificInfoOut->Signaled = EventObject->Header.SignalState;
        } else Status = STATUS_BUFFER_TOO_SMALL;

        *OutBufferLength = sizeof(EVENT_SPECIFIC_INFO_OUT);
      } else if (wcsncmp(ObjectTypeName->Buffer, L"Semaphore", wcslen(L"Semaphore")) == 0) {
        if (*OutBufferLength >= sizeof(SEMAPHORE_SPECIFIC_INFO_OUT)) {
          SemaphoreObject = (PKSEMAPHORE)Object;
          SemaphoreSpecificInfoOut = (PSEMAPHORE_SPECIFIC_INFO_OUT)OutBuffer;
		  SemaphoreSpecificInfoOut->Counter = SemaphoreObject->Header.SignalState;
		  SemaphoreSpecificInfoOut->Limit = SemaphoreObject->Limit;
        } else Status = STATUS_BUFFER_TOO_SMALL;

        *OutBufferLength = sizeof(SEMAPHORE_SPECIFIC_INFO_OUT);
      } else if (wcsncmp(ObjectTypeName->Buffer, L"Mutant", wcslen(L"Mutant")) == 0) {
        if (*OutBufferLength >= sizeof(MUTANT_SPECIFIC_INFO_OUT)) {
          MutantObject = (PKMUTANT)Object;
          MutantSpecificInfoOut = (PMUTANT_SPECIFIC_INFO_OUT)OutBuffer;
          MutantSpecificInfoOut->Abandoned = MutantObject->Abandoned;
          MutantSpecificInfoOut->Signaled = MutantObject->Header.SignalState;
          MutantSpecificInfoOut->OwnerThreadId = 0;
          if (MutantObject->OwnerThread != NULL)
            MutantSpecificInfoOut->OwnerThreadId = GetThreadId((PETHREAD)MutantObject->OwnerThread);
        } else Status = STATUS_BUFFER_TOO_SMALL;

        *OutBufferLength = sizeof(MUTANT_SPECIFIC_INFO_OUT);
	  } else Status = STATUS_NOT_IMPLEMENTED;

      OBReleaseObjectPointer(ObjectType);
	}
  }

  KdPrint(("services.c: GetObjectSpecificInfoService(-):0x%x, *OutBufferLength=%u\n", Status, *OutBufferLength));
  return Status;
}
