
/**
 * @file regcallback.c
 *
 * Implementuje operace instalace a odinstalace zpetne volane funkce pro
 * monitorovani registru.
 */

#include <ntddk.h>
#include "driver.h"
#include "regevents.h"
#include "regcallback.h"

// cookie, ktera identifikuje nasi zpetne volanou funkci v ramci seznamu
// techto rutin pro monitorovani registru
static LARGE_INTEGER cm_cookie;


/** Zpetne volana funkce pro monitorovani operaci nad registrem.
 *
 *  Tuto rutinu jadro zavola, kdykoliv ma dojit, nebo prave doslo k nejake
 *  operaci nad registrem.  Rutina zajisti vytvoreni prislusneho zaznamu udalosti
 *  popisujici danou udalost (v pripade pre notifikace), pripadne dokonceni uprav existujiciho zaznamu
 *  udalosti (v pripade post notifikace).
 *
 *  @return Funkce vraci vzdy STATUS_SUCCESS, protoze pouze monitoruje, neblokuje
 *  a ani nemeni chovani danych operaci.
 */
NTSTATUS RegistryCallback(IN PVOID Context, IN PVOID Argument1, IN PVOID Argument2)
{
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("regcallback.c: RegistryCallback(Context=%p;Argument1=0x%p; Argument2=0x%p)\n", Context, Argument1, Argument2));

  switch ((REG_NOTIFY_CLASS)Argument1)
  {
    case RegNtPreDeleteKey: ParseDeleteKeyEvent((PREG_DELETE_KEY_INFORMATION)Argument2);           break;
    case RegNtPreSetValueKey: ParseSetValueKeyEvent((PREG_SET_VALUE_KEY_INFORMATION)Argument2);          break;
    case RegNtPreDeleteValueKey: ParseDeleteValueKeyEvent((PREG_DELETE_VALUE_KEY_INFORMATION)Argument2);         break;
    case RegNtPreSetInformationKey: ParseSetInformationKeyEvent((PREG_SET_INFORMATION_KEY_INFORMATION)Argument2);            break;
    case RegNtPreRenameKey: ParseRenameKeyEvent((PREG_RENAME_KEY_INFORMATION)Argument2);     break;
    case RegNtPreEnumerateKey: ParseEnumerateKeyEvent((PREG_ENUMERATE_KEY_INFORMATION)Argument2);        break;
    case RegNtPreEnumerateValueKey: ParseEnumerateValueKeyEvent((PREG_ENUMERATE_VALUE_KEY_INFORMATION)Argument2);          break;
    case RegNtPreQueryKey: ParseQueryKeyEvent((PREG_QUERY_KEY_INFORMATION)Argument2);            break;
    case RegNtPreQueryValueKey: ParseQueryValueKeyEvent((PREG_QUERY_VALUE_KEY_INFORMATION)Argument2);          break;
    case RegNtPreQueryMultipleValueKey: ParseQueryMultipleValueKeyEvent((PREG_QUERY_MULTIPLE_VALUE_KEY_INFORMATION)Argument2);       break;
    case RegNtPreCreateKey: ParseCreateKeyEvent((PREG_PRE_CREATE_KEY_INFORMATION)Argument2);        break;
    case RegNtPreOpenKey: ParseOpenKeyEvent((PREG_PRE_OPEN_KEY_INFORMATION)Argument2);         break;
    case RegNtPreKeyHandleClose: ParseKeyHandleCloseEvent((PREG_KEY_HANDLE_CLOSE_INFORMATION)Argument2);          break;
    case RegNtPreFlushKey: ParseFlushKeyEvent((PREG_FLUSH_KEY_INFORMATION)Argument2);            break;
    case RegNtPreCreateKeyEx: ParseCreateKeyExEvent((PREG_CREATE_KEY_INFORMATION)Argument2);      break;
    case RegNtPreOpenKeyEx: ParseOpenKeyExEvent((PREG_OPEN_KEY_INFORMATION)Argument2);       break;
    case RegNtPreLoadKey: ParseLoadKeyEvent((PREG_LOAD_KEY_INFORMATION)Argument2);           break;
    case RegNtPreUnLoadKey: ParseUnLoadKeyEvent((PREG_UNLOAD_KEY_INFORMATION)Argument2);          break;
    case RegNtPreQueryKeySecurity: ParseQueryKeySecurityEvent((PREG_QUERY_KEY_SECURITY_INFORMATION)Argument2);      break;
    case RegNtPreSetKeySecurity: ParseSetKeySecurityEvent((PREG_SET_KEY_SECURITY_INFORMATION)Argument2);      break;
    case RegNtPreRestoreKey: ParseRestoreKeyEvent((PREG_RESTORE_KEY_INFORMATION)Argument2);         break;
    case RegNtPreSaveKey: ParseSaveKeyEvent((PREG_SAVE_KEY_INFORMATION)Argument2);          break;
    case RegNtPreReplaceKey: ParseReplaceKeyEvent((PREG_REPLACE_KEY_INFORMATION)Argument2);         break;

    case RegNtPostDeleteKey:
    case RegNtPostSetValueKey:
    case RegNtPostDeleteValueKey:
    case RegNtPostSetInformationKey:
    case RegNtPostRenameKey:
    case RegNtPostEnumerateKey:
    case RegNtPostEnumerateValueKey:
    case RegNtPostQueryKey:
    case RegNtPostQueryValueKey:
    case RegNtPostQueryMultipleValueKey:
    case RegNtPostKeyHandleClose:
    case RegNtPostFlushKey:
    case RegNtPostLoadKey:
    case RegNtPostUnLoadKey:
    case RegNtPostQueryKeySecurity:
    case RegNtPostSetKeySecurity:
      ParseGeneralPostEvent((REG_NOTIFY_CLASS)Argument1, (PREG_POST_OPERATION_INFORMATION)Argument2);
      break;

    case RegNtPostCreateKey:
      ParsePostCreateKeyEvent((PREG_POST_CREATE_KEY_INFORMATION)Argument2);
      break;

    case RegNtPostOpenKey:
      ParsePostOpenKeyEvent((PREG_POST_OPEN_KEY_INFORMATION)Argument2);
      break;

    case RegNtPostCreateKeyEx:
      ParsePostCreateKeyExEvent((PREG_POST_OPERATION_INFORMATION)Argument2);
      break;

    case RegNtPostOpenKeyEx:
      ParsePostOpenKeyExEvent((PREG_POST_OPERATION_INFORMATION)Argument2);
      break;

    case RegNtPostSaveKey:
      ParsePostSaveKeyEvent((PREG_SAVE_KEY_INFORMATION)Argument2);
      break;

    case RegNtPostReplaceKey:
      ParsePostReplaceKeyEvent((PREG_REPLACE_KEY_INFORMATION)Argument2);
      break;

    case RegNtPostRestoreKey:
      ParsePostRestoreKeyEvent((PREG_RESTORE_KEY_INFORMATION)Argument2);
      break;

    default:
      KdPrint(("regcallback.c: RegistryCallback(): Neznamy typ udalosti!\n"));
      break;
  }

  // Tento ovladac pouze monitoruje. Aby nenarusil normalni beh operaci,
  // vzdy vraci uspech.
  Status = STATUS_SUCCESS;
  
  KdPrint(("regcallback.c: RegistryCallback(-):0x%x\n", Status));
  return Status;
}



/** Zaregistruje nasi zpetne volanou funkci pro odber udalosti nad registrem.
 *
 *  @return Funkce vrati hodnotu NTSTATUS indikujici uspech ci neuspech
 *  operace.
 */
NTSTATUS RegCallbackInit(VOID)
{
  NTSTATUS Status = STATUS_UNSUCCESSFUL;
  KdPrint(("regcallback.c: RegCallbackInit()\n"));

  Status = CmRegisterCallback(RegistryCallback, NULL, &cm_cookie);

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


/** Odregistruje zpetne volanou funkci z odberu registrovych udalosti.
 */
VOID RegCallbackFinit(VOID)
{
  KdPrint(("regcallback.c: RegCallbackFinit()\n"));

  CmUnRegisterCallback(cm_cookie);

  KdPrint(("regcallback.c: RegCallbackFinit(-)\n"));
  return;
}
