
/**
 * @file: object_type.c
 *
 * Tento soubor je soucasti frameworku pro praci s internimi datovymi strukturami spravce
 * objektu jadra Windows. V tomto souboru jsou implementovany rutiny pro praci s telem
 * objektu typu, ktere popisuje struktura OBJECT_TYPE.
 */

#include <ntddk.h>
#include "version.h"
#include "driver.h"
#include "object_type.h"

// Cislo verze operacniho systemu, na kterem ovladac aktualne bezi
static ULONG VersionCode = VERSION_UNKNOWN;



/** Vrati polozku TypeList struktury OBJECT_TYPE.
 *
 * @param ObjectType Adresa tela objektu typu.
 *
 * @return Funkce vrati adresu struktury LIST_ENTRY ulozene v polozce TypeList struktury
 * OBJECT_TYPE. Tato struktura je hlavou spojoveho seznamu propojujiciho vsechny objekty
 * stejneho typu (pres hlavicky OBJECT_HEADER_CREATOR_INFO). Tento seznam existuje, pokud
 * dany typ objektu ma nastaven priznak MaintainTypeList. Funkce by nemela nikdy selhat.
 */
PLIST_ENTRY OTGetTypeList(POBJECT_TYPE ObjectType)
{
  PLIST_ENTRY Ret = NULL;
  KdPrint(("object_type.c: OTGetTypeList(ObjectType=0x%p)\n", ObjectType));

  switch (VersionCode) {
    case VERSION_W2K: Ret = OTW2KTypeList(ObjectType); break;
    case VERSION_WXP: Ret = OTWXPTypeList(ObjectType); break;
    case VERSION_W2K3: Ret = OTW2K3TypeList(ObjectType); break;
    case VERSION_VISTA: Ret = OTVistaTypeList(ObjectType); break;
    case VERSION_W7: Ret = OTW7TypeList(ObjectType); break;
	default:
      KdPrint(("object.c: OTGetTypeList(): OS version is not supported\n"));
      break;
  }

  KdPrint(("object_type.c: OTGetTypeList(-):0x%p", Ret));
  return Ret;
}


/** Vrati adresu struktury UNICODE_STRING obsahujici jmeno objektu typu.
 *
 * Funkce neprovadi se jmenem objektu typu zadne operace (hluboke kopie atd.). Pouze vrati
 * adresu polozky Name struktury OBJECT_TYPE.
 *
 * @param ObjectType Adresa tela objektu typu.
 *
 * @return Funkce vraci adresu struktury UNICODE_STRING se jmenem objektu typu. Funkce
 * by mela vzdy vratit platnou adresu.
 */
PUNICODE_STRING OTGetName(POBJECT_TYPE ObjectType)
{
  PUNICODE_STRING Ret = NULL;
  KdPrint(("object_type.c: OTGetName(ObjectType=0x%p)\n", ObjectType));

  switch (VersionCode) {
    case VERSION_W2K: Ret = OTW2KName(ObjectType); break;
    case VERSION_WXP: Ret = OTWXPName(ObjectType); break;
    case VERSION_W2K3: Ret = OTW2K3Name(ObjectType); break;
    case VERSION_VISTA: Ret = OTVistaName(ObjectType); break;
    case VERSION_W7: Ret = OTW7Name(ObjectType); break;
	default:
      KdPrint(("object.c: OTGetName(): OS version is not supported\n"));
      break;
  }

  KdPrint(("object_type.c: OTGetName(-):0x%S", Ret->Buffer));
  return Ret;
}


/** Vrati hodnotu polozky DefaultObject struktury OBJECT_TYPE.
 *
 * @param ObjectType Adresa tela objektu typu.
 *
 * @return Funkce vraci hodnotu polozky DefaultObject struktury OBJECT_TYPE. Nemela by
 * nikdy selhat.
 */
PVOID OTGetDefaultObject(POBJECT_TYPE ObjectType)
{
  PVOID Ret = NULL;
  KdPrint(("object_type.c: OTGetDefaultObject(ObjectType=0x%p)\n", ObjectType));

  switch (VersionCode) {
    case VERSION_W2K: Ret = OTW2KDefaultObject(ObjectType); break;
    case VERSION_WXP: Ret = OTWXPDefaultObject(ObjectType); break;
    case VERSION_W2K3: Ret = OTW2K3DefaultObject(ObjectType); break;
    case VERSION_VISTA: Ret = OTVistaDefaultObject(ObjectType); break;
    case VERSION_W7: Ret = OTW7DefaultObject(ObjectType); break;
	default:
      KdPrint(("object.c: OTGetDefaultObject(): OS version is not supported\n"));
      break;
  }

  KdPrint(("object_type.c: OTGetDefaultObject(-):0x%p", Ret));
  return Ret;
}


/** Vraci hodnotu polozky Index struktury OBJECT_TYPE. Jedna se o index daneho objektu typu.
 *
 * @param ObjectType Adresa tela objektu typu.
 *
 * @return Vrati hodnotu polozky Index struktury OBJECT_TYPE. V pripade neuspechu, ktery
 * by nemel nikdy nastat, vrati hodnotu 0xFFFFFFFF.
 */
ULONG OTGetIndex(POBJECT_TYPE ObjectType)
{
  ULONG Ret = 0xFFFFFFFF;
  KdPrint(("object_type.c: OTGetIndex(ObjectType=0x%p)\n", ObjectType));

  switch (VersionCode) {
    case VERSION_W2K: Ret = OTW2KIndex(ObjectType); break;
    case VERSION_WXP: Ret = OTWXPIndex(ObjectType); break;
    case VERSION_W2K3: Ret = OTW2K3Index(ObjectType); break;
    case VERSION_VISTA: Ret = OTVistaIndex(ObjectType); break;
    case VERSION_W7: Ret = OTW7Index(ObjectType); break;
	default:
      KdPrint(("object.c: OTGetIndex(): OS version is not supported\n"));
      break;
  }

  KdPrint(("object_type.c: OTGetIndex(-):%u", Ret));
  return Ret;
}


/** Vrati statisticke informace o poctech objektu daneho typu
 *
 * Tyto statisticke informace sestavaji z:
 *    Aktualni pocet objektu daneho typu,
 *    Nejvyssi dosazeny pocet objektu daneho typu behem aktualniho behu pocitace,
 *    Aktualni pocet handle na objekty daneho typu,
 *    Nejvyssi dosazeny pocet handle na objekty daneho typu behem aktualniho behu pocitace.
 *
 * @param ObjectType Adresa tela objektu typu.
 * @param Statistics Adrwsa struktury OBJECT_TYPE_STATISTICS, do ktere funkce v pripade
 * uspechu ulozi vyse popsane statistiky.
 *
 * @return Funkce vraci hodnotu NTSTATUS indikujici uspech nebo neuspech.
 */
NTSTATUS OTGetStatistics(POBJECT_TYPE ObjectType, POBJECT_TYPE_STATISTICS Statistics)
{
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("object_type.c: OTGetStatistics(ObjectType=0x%p; Statistics=0x%p)\n", ObjectType, Statistics));

  Status = STATUS_SUCCESS;
  switch (VersionCode) {
    case VERSION_W2K:
      Statistics->TotalNumberOfHandles = OTW2KTotalNumberOfHandles(ObjectType);
      Statistics->TotalNumberOfObjects = OTW2KTotalNumberOfObjects(ObjectType);
      Statistics->HighWaterNumberOfHandles = OTW2KHighWaterNumberOfHandles(ObjectType);
      Statistics->HighWaterNumberOfObjects = OTW2KHighWaterNumberOfObjects(ObjectType);
      break;

    case VERSION_WXP:
      Statistics->TotalNumberOfHandles = OTWXPTotalNumberOfHandles(ObjectType);
      Statistics->TotalNumberOfObjects = OTWXPTotalNumberOfObjects(ObjectType);
      Statistics->HighWaterNumberOfHandles = OTWXPHighWaterNumberOfHandles(ObjectType);
      Statistics->HighWaterNumberOfObjects = OTWXPHighWaterNumberOfObjects(ObjectType);
      break;

    case VERSION_W2K3:
      Statistics->TotalNumberOfHandles = OTW2K3TotalNumberOfHandles(ObjectType);
      Statistics->TotalNumberOfObjects = OTW2K3TotalNumberOfObjects(ObjectType);
      Statistics->HighWaterNumberOfHandles = OTW2K3HighWaterNumberOfHandles(ObjectType);
      Statistics->HighWaterNumberOfObjects = OTW2K3HighWaterNumberOfObjects(ObjectType);
      break;

    case VERSION_VISTA:
      Statistics->TotalNumberOfHandles = OTVistaTotalNumberOfHandles(ObjectType);
      Statistics->TotalNumberOfObjects = OTVistaTotalNumberOfObjects(ObjectType);
      Statistics->HighWaterNumberOfHandles = OTVistaHighWaterNumberOfHandles(ObjectType);
      Statistics->HighWaterNumberOfObjects = OTVistaHighWaterNumberOfObjects(ObjectType);
      break;

   case VERSION_W7:
      Statistics->TotalNumberOfHandles = OTW7TotalNumberOfHandles(ObjectType);
      Statistics->TotalNumberOfObjects = OTW7TotalNumberOfObjects(ObjectType);
      Statistics->HighWaterNumberOfHandles = OTW7HighWaterNumberOfHandles(ObjectType);
      Statistics->HighWaterNumberOfObjects = OTW7HighWaterNumberOfObjects(ObjectType);
      break;

   default:
      KdPrint(("object_type.c: OTGetStatistics(): OS version is not supported\n"));
	  Status = STATUS_NOT_SUPPORTED;
      break;
  }

  KdPrint(("object_type.c: OTGetStatistics(-):0x%x, %u:%u:%u:%u", Status, Statistics->TotalNumberOfHandles, Statistics->TotalNumberOfObjects, Statistics->HighWaterNumberOfHandles, Statistics->HighWaterNumberOfObjects));
  return Status;
}


/** Vrati adresu polozky TypeInfo struktury OBJECT_TYPE.
 *
 * Polozka TypeInfo je strukturou OBJECT_TYPE_INITIALIZER, ktera obsahuje mnoho zajimavych
 * informaci o objektech daneho typu. Rutiny pro jeji zkoumani implementuje soubor
 * object_initializer.c.
 *
 * @param ObjectType Adresa tela objektu typu.
 *
 * @return Funkce vraci adresu struktury OBJECT_INITIALIZER. Tato struktura je ulozena
 * v polozce TypeInfo struktury OBJECT_TYPE. Dochazi pouze k vraceni adresy, zadnym
 * hlubokym kopiim.
 */
PVOID OTGetTypeInfo(POBJECT_TYPE ObjectType)
{
  PVOID Ret = NULL;
  KdPrint(("object_type.c: OTGetTypeInfo(ObjectType=0x%p)\n", ObjectType));

  switch (VersionCode) {
    case VERSION_W2K: Ret = OTW2KTypeInfo(ObjectType); break;
    case VERSION_WXP: Ret = OTWXPTypeInfo(ObjectType); break;
    case VERSION_W2K3: Ret = OTW2K3TypeInfo(ObjectType); break;
    case VERSION_VISTA: Ret = OTVistaTypeInfo(ObjectType); break;
    case VERSION_W7: Ret = OTW7TypeInfo(ObjectType); break;
	default:
      KdPrint(("object.c: OTGetTypeInfo(): OS version is not supported\n"));
      break;
  }

  KdPrint(("object_type.c: OTGetTypeInfo(-):0x%p", Ret));
  return Ret;
}


/** Vrati hodnotu polozky Key struktury OBJECT_TYPE.
 *
 * Polozka Key obsahuje hodnotu, ktera se pouziva jako tag pri alokaci pameti pro objekty
 * daneho typu.
 *
 * @param ObjectType Adresa tela objektu typu.
 *
 * @return Funkce vraci hodnotu polozky Key struktury OBJECT_TYPE.
 */
ULONG OTGetKey(POBJECT_TYPE ObjectType)
{
  ULONG Ret = 0xFFFFFFFF;
  KdPrint(("object_type.c: OTGetKey(ObjectType=0x%p)\n", ObjectType));

  switch (VersionCode) {
    case VERSION_W2K: Ret = OTW2KKey(ObjectType); break;
    case VERSION_WXP: Ret = OTWXPKey(ObjectType); break;
    case VERSION_W2K3: Ret = OTW2K3Key(ObjectType); break;
    case VERSION_VISTA: Ret = OTVistaKey(ObjectType); break;
    case VERSION_W7: Ret = OTW7Key(ObjectType); break;
	default:
      KdPrint(("object.c: OTGetKey(): OS version is not supported\n"));
      break;
  }

  KdPrint(("object_type.c: OTGetKey(-):0x%x", Ret));
  return Ret;
}


/** Vrati vsechny udaje obsazene ve strukture OBJECT_TYPE, vcetne podrobnosti ve
 * strukture OBJECT_TYPE_INITIALIZER.
 *
 * Tato rutina je minena jako takova zkratka, pokud potrebujete ziskat ze struktury
 * OBJECT_TYPE veskere dulezite informace.
 *
 * Rutina dela hlubokou kopii jmena objektu. Pamet zabrana retezcem jnema je tedy nutne
 * uvolnit, jakmile s ni volajici jiz nepotrebuje pracovat.
 *
 * @param Object Adresa tela objektu typu.
 * @param Info Adresa struktury, kterou rutina v pripade uspechu naplni informacemi
 * o danem objektu typu.
 *
 * @return Funkce vraci hodnotu NTSTATUS indikujici uspech ci neuspech operace.
 */
NTSTATUS OTGetSpecificInfo(POBJECT_TYPE Object, POBJECT_TYPE_INFO Info)
{
  PVOID Initializer = NULL;
  PWCHAR Tmp = NULL;
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("object_type.c: OTGetSpecificInfo(Object=0x%p; Info=0x%p)\n", Object, Info));

  RtlZeroMemory(Info, sizeof(OBJECT_TYPE_INFO));
  Info->DefaultObject = OTGetDefaultObject(Object);
  Info->Index = OTGetIndex(Object);
  Info->Key = OTGetKey(Object);
  Info->TypeList = *OTGetTypeList(Object);
  Status = OTGetStatistics(Object, &Info->Statistics);
  if (NT_SUCCESS(Status)) {
    Info->Name = *OTGetName(Object);
    if (Info->Name.Buffer != NULL) {
      Tmp = (PWCHAR)ExAllocatePoolWithTag(PagedPool, Info->Name.Length + sizeof(WCHAR), POOL_TAG);
      if (Tmp != NULL) {
        RtlZeroMemory(Tmp, Info->Name.Length + sizeof(WCHAR));
		RtlCopyMemory(Tmp, Info->Name.Buffer, Info->Name.Length);
		Info->Name.Buffer = Tmp;
      } else Status = STATUS_INSUFFICIENT_RESOURCES;
	}

	if (NT_SUCCESS(Status)) {
	  Initializer = OTGetTypeInfo(Object);
      if (Initializer != NULL) {
        Status = OTIGetFlags(Initializer, &Info->InitializerFlags);
		if (NT_SUCCESS(Status)) {
          Status = OTIGetMethods(Initializer, &Info->InitializerMethods);
          if (NT_SUCCESS(Status)) {
            Status = OTIGetOtherInfo(Initializer, &Info->InitializerOtherInfo);
          }
		}
      } else Status = STATUS_UNSUCCESSFUL;
    }

    if (!NT_SUCCESS(Status)) {
      if (Info->Name.Buffer != NULL)
        ExFreePoolWithTag(Info->Name.Buffer, POOL_TAG);

	  RtlZeroMemory(Info, sizeof(OBJECT_TYPE_INFO));
	}
  }

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



/** Provadi inicializaci modulu pro praci s objekty typu (strukturami OBJECT_TYPE).
 *
 * Rutina pouze naplni promennou VersionCode cislem verze operacniho systemu, na kterem
 * ovladac prave bezi.
 *
 * @return Funkce vraci hodnotu NTSTATUS indikujici uspech ci neuspech operace.
 */
NTSTATUS OTModuleInit(VOID)
{
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("object_type.c: OTModuleInit()\n"));

  VersionCode = GetVersionCode();
  if (VersionCode != VERSION_UNKNOWN)
    Status = STATUS_SUCCESS;
  else Status = STATUS_NOT_SUPPORTED;

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


/** Provadi uklid modulu pro praci s objekty typu.
 *
 * Protoze tento modul nezasahuje do struktur spravce objektu a ani jadra, tato rutina
 * nedela nic.
 */
VOID OTModuleFinit(VOID)
{
  KdPrint(("object_type.c: OTModuleFinit()\n"));

  KdPrint(("object_type.c: OTModuleFinit(-)\n"));
  return;
}
