/* ndc for windows NT/Win 95 by l. kahn
 (c) 1996 */

#include <stdio.h>
#include <windows.h>
#include <io.h>
#include <process.h>
#include "../conf/portability.h"
#include "../compat/lib/log.h"

void usage();
void start_up_bind();
void service_calls();
void use_mailslots();
BOOL onnt;
void
main(argc, argv)
	int argc;
	char *argv[];
{
BOOL usemailslot = FALSE;

if (argc < 2 || argc > 4) {
	usage();
	exit(1);
	}

onnt = OnWinnt();	

/* services stuff don't work on win95 so if not on winnt must use mailslots
   to communicate to a win95 server */
 
if (onnt != TRUE)
   usemailslot = TRUE;
   
else if ((argc == 4) && (strcmp(argv[3], "-MS") == 0))
   {
	usemailslot = TRUE;
   }
	
if (usemailslot == TRUE)
	use_mailslots(argc, argv);
else
	service_calls(argc, argv);
exit(0);
}

void
use_mailslots(argc, argv)
	int argc;
	char *argv[];
{

#define              SZ_NAME_BUF 30
char    inbuf[160];
char    outbuf[160];
char    commonbuf[160];
DWORD   bytesRead, bytesWritten;
BOOL    ret, ret2, ret3;
#define               SZ_SLOT_NAME_BUF 50
UCHAR   ucSlotNameBuf[SZ_SLOT_NAME_BUF] = "";
LPTSTR  lpszSlotName = (LPTSTR)&ucSlotNameBuf;
UCHAR   ucOperation = '\0';
UCHAR   ucMchNameBuf[SZ_NAME_BUF] = "";
LPTSTR  lpszMchName = (LPTSTR)&ucMchNameBuf;
char myname[100];
DWORD nsize = 99;
char myname2[102];
HANDLE outslot;
HANDLE inslot;
BOOL running;
char tickbuf[20];
BOOL onlocalmachine = FALSE;
BOOL rv = FALSE;

  rv = GetComputerName((char *)&myname,&nsize);
  if (rv != TRUE)
    { 
      fprintf(stderr,"GetComputerName failed %d \n",WSAGetLastError());
      exit(1);
    }

  strcpy(myname2, "\\\\");
  strcat(myname2,myname);

   if (argc == 2)
     strcpy(lpszMchName,myname2);
   else
    {
     strcpy(lpszMchName,argv[2]);
    }



  onlocalmachine = TRUE;
  if (strcmp(myname2,lpszMchName) != 0)
       onlocalmachine = FALSE;
    
  strcpy(lpszSlotName,lpszMchName);
  strcat(lpszSlotName,"\\mailslot\\sd_bind");

  outbuf[0] = ucOperation;
  outbuf[1] = '\0';

  // because of a bug in the mailbox stuff we have to put the tickcount as the first param otherwise it gets the
  // message once for each bound transport...
   strcpy(commonbuf,myname);
   strcat(commonbuf," ");
   strcat(commonbuf,"sd_ndc ");




	if (!stricmp(argv[1], "start"))
          {
           BOOL running = FALSE;
           // lgk first try status command to see if already running
           // so we don't start it again.
           if (onnt)
             {
               fprintf(stderr,"Cannot use \"ndc start\" to start the service under Windows NT!\n");
               fprintf(stderr," You must be on a Windows NT machine (or don't use the -MS flag)\n");
               fprintf(stderr,"to startup bind on the same/another WIndows NT machine.\n");
               fprintf(stderr,"This is due to windows NT security restrictions!\n");
               exit(1);
             }

            if (!onlocalmachine)
             {
               fprintf(stderr,"You cannot start up bind on a remote machine using the mailslot\n");
               fprintf(stderr,"version of ndc.\n");
               fprintf(stderr,"This is due to security restrictions.\n");
               fprintf(stderr,"Please log on %s directly to start bind!\n",lpszMchName);
               exit(1);
             }

             // open our slot for responses 
             // open our mail slot no security needed on incomming...
             inslot = CreateMailslot("\\\\.\\mailslot\\sd_ndc",0,7000,NULL);

             if (inslot != INVALID_HANDLE_VALUE)
               {
                // possibley running .. not sure yet as this returns true if checking a remote machine
                strcpy(outbuf,commonbuf);
                strcat(outbuf,"status ");
                sprintf(tickbuf,"%d",GetTickCount());
                strcat(outbuf,tickbuf);
                outslot = CreateFile(lpszSlotName,GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,
                               FILE_ATTRIBUTE_NORMAL,NULL);

                 // outslot should always open regardless
                 if (outslot == INVALID_HANDLE_VALUE)
                  {
     	          fprintf(stderr, "Error: Couldn't create mail slot (outgoing) %s ... errorcode = %d \n",lpszSlotName,GetLastError());
                    CloseHandle(inslot);
                    exit(1);
                  }

                  // go on now both mail slots are open
                  ret = FALSE;
                  ret2 = FALSE;
                  ret = WriteFile(
                     outslot,       // file to write to
                     &outbuf,         // address of output buffer
                     strlen(outbuf) + 1, // number of bytes to write
                     &bytesWritten,  // number of bytes written
                     NULL);          // overlapped stuff, not needed
    
                 if (ret) // wrote ok if id didn't the server may not be runing even though the inslot 
                          // opened ok due to the fact that it may be on a remote machine..
                   {
                    ret2 = ReadFile(
                        inslot,     // file to read from
                        &inbuf,          // address of input buffer
                        sizeof(inbuf),  // number of bytes to read
                        &bytesRead,     // number of bytes read
                        NULL);          // overlapped stuff, not needed

                   // ok if ret2 is true it means it is already running
                   if (ret2)
                     {
                      running = TRUE;
                      }
                   else // not running
                    {
                     running = FALSE;
                    }

                  } // ret ok or not

                 else // write did't work not running
                 {
                  running = FALSE;
                 }

                } // inslot opened ok or not

              else // open inslot didn't work .. not running
                 {
                  running = FALSE;
                 }

            // now based on running handle it
            if (!running)
             {
              // set to start
              CloseHandle(inslot);
              CloseHandle(outslot);
              start_up_bind();
	      fprintf(stdout, "Name Server Started\n");
	      exit(0);
             }
            else // already running
             {
     	      fprintf(stderr, "Domain Name Service already running\n");
              CloseHandle(inslot);
              CloseHandle(outslot);
	      exit(1);
             }
   } // end of start

 else if (!stricmp(argv[1], "restart"))
   {

   if (onnt)
     {
       fprintf(stderr,"Cannot use \"ndc restart\" to restart the service under Windows NT!\n");
       fprintf(stderr," You must be on a Windows NT machine (or don't use the -MS flag\n");
       fprintf(stderr," to startup bind on the same/another Windows NT machine.\n");
       fprintf(stderr," This is due to windows NT security restrictions!\n");
       exit(1);
     }
       
            if (!onlocalmachine)
             {
               fprintf(stderr,"You cannot restart bind on a remote machine using the mailslot\n");
               fprintf(stderr,"Version of ndc.\n");
               fprintf(stderr,"This is due to security restrictions.\n");
               fprintf(stderr,"Please log on %s directly to start bind!\n",lpszMchName);
               exit(1);
             }

             // open our slot for responses 
             // open our mail slot no security needed on incomming...
             inslot = CreateMailslot("\\\\.\\mailslot\\sd_ndc",0,7000,NULL);

             if (inslot != INVALID_HANDLE_VALUE)
               {
                // possibly running .. not sure yet as this returns true if checking a remote machine
                strcpy(outbuf,commonbuf);
                strcat(outbuf,"status ");
                sprintf(tickbuf,"%d",GetTickCount());
                strcat(outbuf,tickbuf);
  
                outslot = CreateFile(lpszSlotName,GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,
                               FILE_ATTRIBUTE_NORMAL,NULL);

                 // outslot should always open regardless
                 if (outslot == INVALID_HANDLE_VALUE)
                  {
     	          fprintf(stderr, "Error: Couldn't create mail slot (outgoing) %s ... errorcode = %d \n",lpszSlotName,GetLastError());
                    CloseHandle(inslot);
                    exit(1);
                  }

                  // go on now both mail slots are open
                  ret = FALSE;
                  ret2 = FALSE;
                  ret = WriteFile(
                     outslot,       // file to write to
                     &outbuf,         // address of output buffer
                     strlen(outbuf) + 1, // number of bytes to write
                     &bytesWritten,  // number of bytes written
                     NULL);          // overlapped stuff, not needed
    
                 if (ret) // wrote ok if id didn't the server may not be runing even though the inslot 
                          // opened ok due to the fact that it may be on a remote machine..
                   {
                    ret2 = ReadFile(
                        inslot,     // file to read from
                        &inbuf,          // address of input buffer
                        sizeof(inbuf),  // number of bytes to read
                        &bytesRead,     // number of bytes read
                        NULL);          // overlapped stuff, not needed

                   // ok if ret2 is true it means it is already running
                   if (ret2)
                     {
                      running = TRUE;
                      }
                   else // not running
                    {
                     running = FALSE;
                    }

                  } // ret ok or not

                 else // write did't work not running
                 {
                  running = FALSE;
                 }

                } // inslot opened ok or not

              else // open inslot didn't work .. not running
                 {
                  running = FALSE;
                 }

            if (!running)
              {
                // it is not running so just start it
                // set to start
                CloseHandle(outslot);
                CloseHandle(inslot);
                start_up_bind();
	        fprintf(stdout, "Name Server Restarted\n");
	        exit(0);
              }
             else
               // aleady running stop/start it
               {
                 // stop it first
                 ret3 = FALSE;
                 strcpy(outbuf,commonbuf);
                 strcat(outbuf,"stop ");
                 sprintf(tickbuf,"%d",GetTickCount());
                 strcat(outbuf,tickbuf);

                 ret3 = WriteFile(
                        outslot,       // file to write to
                        &outbuf,         // address of output buffer
                        strlen(outbuf) + 1, // number of bytes to write
                        &bytesWritten,  // number of bytes written
                        NULL);          // overlapped stuff, not needed
                  if (!ret3)
                    {
	             fprintf(stderr, "Unable to restart the Domain Name Service: %d\n", GetLastError());
                     CloseHandle(inslot);
                     CloseHandle(outslot);
                     exit(1);
                    }  
                  else // shutdown ok
                   { // now give it time to stop
                     CloseHandle(outslot);
                     CloseHandle(inslot);
                     Sleep(7000);
                     start_up_bind();
                     fprintf(stdout,"Name Server Restarted\n");
                     exit(0);
                   } // shutdown ok
             } // already running

	   } // end of restart
      else // not start/restart
       { 
	  
	if (!stricmp(argv[1], "stop")) {
  	   fprintf(stdout, "Name Server Stopped\n");
  	   fprintf(stdout, "WARNING: If the remote machine is running Windows NT this command\n");
  	   fprintf(stdout, "         will be ignored!\n");
	} else if (!stricmp(argv[1], "status")) {
	} else if (!stricmp(argv[1], "dumpdb")) {
		fprintf(stdout, "Dumping Database\n");
	} else if (!stricmp(argv[1], "reload")) {
		fprintf(stdout, "Reloading Database\n");
	} else if (!stricmp(argv[1], "stats")) {
		fprintf(stdout, "Dumping Statistics\n");
	} else if (!stricmp(argv[1], "trace")) {
		fprintf(stdout, "Trace Level Incremented\n");
	} else if (!stricmp(argv[1], "notrace")) {
		fprintf(stdout, "Tracing Cleared\n");
	} else if (!stricmp(argv[1], "nolog")) {
		fprintf(stdout, "NoLog Flag Set\n");
	} else if (!stricmp(argv[1], "log")) {
		fprintf(stdout, "NoLog Flag Cleared\n");
	} else if (!stricmp(argv[1], "querylog")
			  || !stricmp(argv[1], "qrylog")) {
		fprintf(stdout, "QueryLogging Toggled\n");
	} else
             {
		usage();
		exit(1);
	     }

       strcpy(outbuf,commonbuf);
       strcat(outbuf,argv[1]);
       strcat(outbuf," ");
       sprintf(tickbuf,"%d",GetTickCount());
       strcat(outbuf,tickbuf);

       ret = FALSE;
       ret2 = FALSE;
       outslot = CreateFile(lpszSlotName,GENERIC_WRITE,FILE_SHARE_READ,NULL,OPEN_EXISTING,
                               FILE_ATTRIBUTE_NORMAL,NULL);

          if (outslot == INVALID_HANDLE_VALUE)
            {
     	    fprintf(stderr, "Error: Couldn't create mail slot (outgoing) %s ... errorcode = %d \n",lpszSlotName,GetLastError());
            exit(1);
            }

         // open our mail slot no security needed on incomming...
         inslot = CreateMailslot("\\\\.\\mailslot\\sd_ndc",0,7000,NULL);

         if (inslot == INVALID_HANDLE_VALUE)
            {
     	    fprintf(stderr, "Error: Couldn't create mail slot (incoming) %s ... errorcode = %d \n",lpszSlotName,GetLastError());
     	    fprintf(stderr, "Error: The server may not be running!\n");
            CloseHandle(outslot);
            exit(1);
            }

            // now write the data
            ret = WriteFile(
                      outslot,       // file to write to
                      &outbuf,         // address of output buffer
                      strlen(outbuf) + 1, // number of bytes to write
                      &bytesWritten,  // number of bytes written
                      NULL);          // overlapped stuff, not needed

            if (!ret)
              {
             if (ERROR_ACCESS_DENIED == GetLastError())
               {
                fprintf(stderr,"\nAccess denied\n on trying to send data to server via mail slot!");
               }
              else if (ERROR_BAD_NETPATH == GetLastError())
               {
                fprintf(stderr,"\nMachine %s not found\n",lpszMchName);
               }
             else
             {
              fprintf(stderr,"\nError trying to send data to server via mail slot! errorcode =  %d \n",GetLastError());
             }
            exit(1);
           }

            CloseHandle(outslot);
            // no response for stop
            if(stricmp(argv[1], "stop") == 0)
            {
             CloseHandle(inslot);
             exit(0);
            }

           // now get the response via other mailslot
           ret2 = ReadFile(
                   inslot,     // file to read from
                   &inbuf,          // address of input buffer
                   sizeof(inbuf),  // number of bytes to read
                   &bytesRead,     // number of bytes read
                   NULL);          // overlapped stuff, not needed

            if (!ret2)
              {
           //  if (ERROR_ACCESS_DENIED == GetLastError())
           //    {
           //     fprintf(stderr,"\nAccess denied\n on trying to get data from server via mail slot!");
           //    }
            //  else 
               if (ERROR_BAD_NETPATH == GetLastError())
               {
                fprintf(stderr,"\nMachine %s not found\n",lpszMchName);
               }
             else
             {
              fprintf(stderr,"\nError trying to get data from server via mail slot! errorcode =  %d \n",GetLastError());
             }
            CloseHandle(inslot);
            exit(1);              
           }
               

	if (strcmp(argv[1], "status") == 0)
          {
  		printf("\nStatus of Domain Name Service:\n");
  		printf("%s\n",inbuf);
                CloseHandle(inslot);
                exit(0);
	 }

       else // not status so then all rest should return ok..
        {
          if (strncmp(inbuf,"Ok",2) == 0)
            {
               CloseHandle(inslot);
               exit(0);
            }
          else
            {
              fprintf(stderr,"Error command failed (invalid response): errorcode = %d \n",GetLastError());
              exit(1);       

            }
	}

   } // not start/restart
 }


//--------------------------------------------------------------------------------------------------
void
usage()
{
	fprintf(stderr, "usage: ndc (status|dumpdb|log|nolog|reload|stats|trace|notrace\
					|querylog|start|stop|restart) [\\\\server [-MS]]\n\n");
	fprintf(stderr,"    The optional parameter -MS is necessary when communicating with\n");
	fprintf(stderr,"    bind running under Windows 95 from a Windows NT machine.\n");
	fprintf(stderr,"    and can be used to control a server under NT using mailslots\n");
	fprintf(stderr,"    rather then the service API's.  However start,stop and restart\n");
	fprintf(stderr,"    will not work on an NT machine for security reasons.\n");
	exit(1);
}


//--------------------------------------------------------------------------------------------------
/* lgk code to start up bind hidden under win95 since there are no services */

void start_up_bind()
{

   STARTUPINFO StartInfo;
   BOOLEAN rvalue;
   PROCESS_INFORMATION phandle;
   static char cline[100] = "named95.exe";
  
    /* Set up members of STARTUPINFO structure. */

    StartInfo.cb = sizeof(STARTUPINFO);
    StartInfo.lpReserved = NULL;
    StartInfo.lpReserved2 = NULL;
    StartInfo.cbReserved2 = 0;
    StartInfo.lpDesktop = NULL;

    // set noshow in case it is a win app
    StartInfo.dwFlags = STARTF_USESHOWWINDOW | STARTF_USEPOSITION;

    StartInfo.lpTitle = NULL;
    StartInfo.dwX = 1000;
    StartInfo.dwY = 1000;
    StartInfo.dwXSize = 0;
    StartInfo.dwYSize = 0;
    StartInfo.dwXCountChars= 0;
    StartInfo.dwYCountChars = 0;
    StartInfo.dwFillAttribute = 0;
    StartInfo.hStdInput = NULL;
    StartInfo.hStdOutput = NULL;
    StartInfo.hStdError = NULL;
    StartInfo.wShowWindow = SW_HIDE;

     rvalue = CreateProcess(NULL,(LPSTR)&cline,NULL,NULL,FALSE,DETACHED_PROCESS,NULL,NULL,&StartInfo,&phandle);
 
	if (rvalue == FALSE)
	  {
 	   
           int ecode = GetLastError();
	   if (ecode == 2)
	     {
	       printf("Startup of named95.exe failed errorcode = 2 (FILE_NOT_FOUND)\n");
	     }
	   else
	     {
	      printf("Startup of named95.exe failed errorcode = %d \n",ecode);
	   	 }

	   fflush(stdout);
	   Sleep(10000);
	   }
	   
	     {
	      DWORD waitval = WaitForInputIdle(phandle.hProcess,5000);
	     }

  	   CloseHandle(phandle.hThread);
	   CloseHandle(phandle.hProcess);

	   }

void
service_calls(argc, argv)
	int argc;
	char *argv[];
{

char szMsgPath[255];
DWORD ControlCode;
HANDLE hSCManager = NULL, hDomainNameService = NULL;
SERVICE_STATUS ServiceStatus;
char *MachineName; // john@optimedia.co.il 

   // john@optimedia.co.il moved param checking before OpenSCManager,
   //                      added support for \\server param
	if (argc < 2 || argc > 3) {
		usage();
		exit(1);
	}

   if (argc == 2)
      MachineName = NULL;
   else
      MachineName = argv [2];

	if((hSCManager = OpenSCManager(
			MachineName, // john@optimedia.co.il Open SCManager on other machine
     		NULL,
     		SC_MANAGER_ALL_ACCESS)) == NULL) {
 		fprintf(stderr, "Unable to open Service Control Manager database on local machine: %u\n", GetLastError());
		exit(1);
	}

  	if((hDomainNameService = OpenService(
       		hSCManager,                              
       		TEXT("DomainNameService"),               
       		SERVICE_ALL_ACCESS)) == NULL) {
		fprintf(stderr, "Unable to open a handle to Domain Name Service: %u\n", GetLastError());
		exit(1);
	}

	if (!stricmp(argv[1], "start")) {
		if(!StartService(hDomainNameService, 0, NULL)) {
			if(GetLastError() == ERROR_SERVICE_ALREADY_RUNNING)
				fprintf(stderr, "Domain Name Service already running\n");
			else
				fprintf(stderr, "Unable to start the Domain Name Service: %u\n", GetLastError());
			exit(1);
		}
		fprintf(stdout, "Name Server Started\n");
		exit(0);
/* lgk add startup code here */
         /* Set the Event-ID message-file name. */
          GetCurrentDirectory(sizeof(szMsgPath), szMsgPath);
          strcat(szMsgPath, "\\named.exe");
          addSourceToRegistry("DNS", szMsgPath);
		
	} else if (!stricmp(argv[1], "stop")) {
		ControlCode = SERVICE_CONTROL_STOP;
		fprintf(stdout, "Name Server Stopped\n");
	} else if (!stricmp(argv[1], "restart")) {
		ControlCode = SERVICE_CONTROL_STOP;
	} else if (!stricmp(argv[1], "status")) {
		ControlCode = SERVICE_CONTROL_INTERROGATE;
	} else if (!stricmp(argv[1], "dumpdb")) {
		ControlCode = SERVICE_CONTROL_DUMPDB;
		fprintf(stdout, "Dumping Database\n");
	} else if (!stricmp(argv[1], "reload")) {
		ControlCode = SERVICE_CONTROL_RELOAD;
		fprintf(stdout, "Reloading Database\n");
	} else if (!stricmp(argv[1], "stats")) {
		ControlCode = SERVICE_CONTROL_STATS;
		fprintf(stdout, "Dumping Statistics\n");
	} else if (!stricmp(argv[1], "trace")) {
		ControlCode = SERVICE_CONTROL_TRACE;
		fprintf(stdout, "Trace Level Incremented\n");
	} else if (!stricmp(argv[1], "notrace")) {
		ControlCode = SERVICE_CONTROL_NOTRACE;
		fprintf(stdout, "Tracing Cleared\n");
	} else if (!stricmp(argv[1], "nolog")) {
		ControlCode = SERVICE_CONTROL_NOLOG;
		fprintf(stdout, "NoLog Flag Set\n");
	} else if (!stricmp(argv[1], "log")) {
		ControlCode = SERVICE_CONTROL_LOG;
		fprintf(stdout, "NoLog Flag Cleared\n");
	} else if (!stricmp(argv[1], "querylog")
			  || !stricmp(argv[1], "qrylog")) {
		ControlCode = SERVICE_CONTROL_QRYLOG;
		fprintf(stdout, "QueryLogging Toggled\n");
	} else {
		usage();
		exit(1);
	}

	if (!ControlService(hDomainNameService, ControlCode, &ServiceStatus)) {
		fprintf(stderr, "Unable to send requested code to the Domain Name Service: %u\n", GetLastError());
		exit(1);
	}
	
	if (!stricmp(argv[1], "status")) {
  		printf("\nStatus of Domain Name Service:\n");
  		printf("  Service Type: 0x%x\n", ServiceStatus.dwServiceType);
  		printf("  Current State: 0x%x\n", ServiceStatus.dwCurrentState);
  		printf("  Controls Accepted: 0x%x\n", ServiceStatus.dwControlsAccepted);
  		printf("  Exit Code: %d\n", ServiceStatus.dwWin32ExitCode);
  		printf("  Service Specific Exit Code: %d\n",
               ServiceStatus.dwServiceSpecificExitCode);
  		printf("  Check Point: %d\n", ServiceStatus.dwCheckPoint);
  		printf("  Wait Hint: %d\n", ServiceStatus.dwWaitHint);
	} else if (!stricmp(argv[1], "restart")) {
		Sleep(5*1000);
		if(!StartService(hDomainNameService, 0, NULL)) {
				fprintf(stderr, "Unable to restart the Domain Name Service: %u\n", GetLastError());
			exit(1);
		}
		fprintf(stdout, "Name Server Restarted\n");
	}
	exit(0);

}

