
/**
 * @file: drv.c
 *
 * Hlavni soubor programu DRV. Tento program dovoluje provadet operace
 * nad ovladaci jadra, presneji: instalovat je, nacitat je do jadra,
 * uvolnovat a odinstalovat je. Podporuje pritom tri mody operaci:
 * - Service Control Manager
 * - NtLoadDriver/NtUnloadDriver
 * - NtSetSystemInformation (pouze nacteni do jadra a pouze pro XP a nizsi).
 *
 * Pouziti:
 * drv  <metoda> <operace> <parametry...>
 *
 * Metody:
 *   -scm      Pouzije sluzeb spravce sluzeb (Service Control Manager)
 *   -ntld     Pouzije nativnich funkci NtLoadDriver a NtUnloadDriver
 *   -ntssi    Pouzije nativni funkci NtSetSystemInformation
 *             
 * Operace:    
 *   install <name> <filename>       Nainstaluje ovladac <filename> pod
 *                                   internim jmenem <name>.
 *   load <name>                     Nacte ovladac interniho jmena <name>
 *                                   do prostoru jadra.
 *   unload <name>                   Uvolni ovladac interniho jmena <name>
 *                                   z prostoru jadra.
 *   uninstall <name>                Odinstaluje ovladac interniho jmena
 *                                   <name>.
 */

#include <stdio.h>
#include <windows.h>
#include "..\shared\common.h"
#include "scmDrivers.h"
#include "ntssiDrivers.h"
#include "ntregDrivers.h"
#include "drv.h"


/** Provede inicializaci vsech soucasti programu.
 *
 * @return Funkce vracti TRUE v pripade uspechu a FALSE v pripade 
 * neuspechu.
 */
BOOL ModulesInit(VOID)
{
  BOOL ret = FALSE;
  DebugMsg(("drv.c: ModulesInit()\n"));
  
  ret = CommonInit();
  if (ret) {
    ret = ntldInit();
    if (ret) {
      ret = ntssiInit();
      if (ret) {
        ret = scmInit();
        if (!ret) {
          DebugMsg(("drv.c: ModulesInit(): call to scmInit() failed\n"));
          ntssiFinit();
          ntldFinit();
          CommonFinit();
        }
      } else {
        DebugMsg(("drv.c: ModulesInit(): call to ntssiInit() failed\n")); 
	    ntldFinit();
		CommonFinit();
	  }
    } else {
      DebugMsg(("drv.c: ModulesInit(): call to ntldInit() failed\n"));
	  CommonFinit();
	}
  } else DebugMsg(("drv.c: ModulesInit(): call to CommonInit() failed\n"));  

  DebugMsg(("drv.c: ModulesInit(-):%u\n", ret));
  return ret;
}


/** Zajisti provedeni uklidu po jednotlivych castech programu.
 *
 * Rutina postupne vola uklizeci funkce jednotlivych casti programu.
 */
VOID ModulesFinit(VOID)
{
  DebugMsg(("drv.c: ModulesFinit()\n"));
  
  scmFinit();
  ntssiFinit();
  ntldFinit();
  CommonFinit();
  
  DebugMsg(("drv.c: ModulesFinit(-)\n"));
  return;
}



/** Hlavni funkce programu. Dovoluje instalovat, nactiat, uvolnovat a
 *  odinstalovavat ovladace jadra. Konkretni operaci provadi na zaklade
 *  argumentu prikazove radky.
 *
 *  @param argc Pocet argumentu prikazove radky (vcetne nazvu programu).
 *  @param argv Pole retezcu s hodnotami argumentu prikazove radky.
 */
int main(int argc, CHAR **argv)
{
  BOOL ret = FALSE;
  INSTALLDRIVERFUNC InstallDriver = NULL;
  UNINSTALLDRIVERFUNC UninstallDriver = NULL;
  LOADDRIVERFUNC LoadDriver = NULL;
  UNLOADDRIVERFUNC UnloadDriver = NULL;

  printf("DRV – Driver Manipulation Utility v1.0\n");
  printf("Copyright (C) Martin Drab 2011\n");

  ret = ModulesInit();
  if (ret) {
    ret = argc >= 4;
    if (ret) {
      BOOL scm, ntssi, ntld = FALSE;
      // Vyber modu operace (SCM, NtLoadDriver, NtSetSystemInformation)
      scm = strcmp(argv[1], METHOD_SCM) == 0;
      ntld = strcmp(argv[1], METHOD_NTLD) == 0;
      ntssi = strcmp(argv[1], METHOD_NTSSI) == 0;
      ret = (scm || ntld || ntssi);
      if (ret) {
        BOOL inst, uninst, load, unload = FALSE;
        // Vyber konkretni operace
        if (scm) {
          InstallDriver = scmInstallDriver;
          LoadDriver = scmLoadDriver;
          UnloadDriver = scmUnloadDriver;
          UninstallDriver = scmUninstallDriver;
        } else if (ntld) {
          InstallDriver = ntldInstallDriver;
          LoadDriver = ntldLoadDriver;
          UnloadDriver = ntldUnloadDriver;
          UninstallDriver = ntldUninstallDriver;
        } else if (ntssi) LoadDriver = ntssiLoadDriver;
          inst = strcmp(argv[2], COMMAND_INSTALL) == 0;
          load = strcmp(argv[2], COMMAND_LOAD) == 0;
          unload = strcmp(argv[2], COMMAND_UNLOAD) == 0;
          uninst = strcmp(argv[2], COMMAND_UNINSTALL) == 0;
          ret = (inst || load || unload || uninst);
          if (ret) {
            ret = (inst) ? (argc == 5) : (argc == 4);
            if (ret) {
              ret = ((inst && InstallDriver != NULL) || (load && LoadDriver != NULL) || (unload && UnloadDriver != NULL) || (uninst && UninstallDriver != NULL));
              if (ret) {
                PWCHAR DriverName = ConvertAnsiStringToUnicode(argv[3]);
                ret = DriverName != NULL;
                if (ret) {
                  if (inst) {
                    PWCHAR DriverFileName = ConvertAnsiStringToUnicode(argv[4]);
                    // Instalace ovladace
                    ret = (DriverFileName != NULL);
                    if (ret) {
                      ret = InstallDriver(DriverName, DriverFileName);

                    FreeUnicodeString(DriverFileName);
                  } else printf("Failed to convert driver file name to unicode string\n");
                } else if (load) {
                  // Nacteni ovladace do jadra
                  ret = LoadDriver(DriverName);
                } else if (unload) {
                  // Uvolneni ovladace z jadra
                  ret = UnloadDriver(DriverName);
                } else if (uninst)
                  // Odinstalovani ovladace
                  ret = UninstallDriver(DriverName);

                  if (ret) {
                    printf("Operace probehla uspesne\n");
                  } else printf("Operace se nezdarila\n");

                  FreeUnicodeString(DriverName);
                } else printf("Failed to convert driver name to unicode string\n");
              } else printf("The seleted method does not support this operation\n");
            } else printf("Invalid number of arguments for the selected operation\n");
          } else printf("Invalid operation selected\n");
        } else printf("Invalid method selected\n");
      } else printf("Not enough arguments\n");
    
    ModulesFinit();
  } else printf("Initialization failed\n");
  
  return (ret) ? 0 : 1;
}
