Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

win32_service.c

Go to the documentation of this file.
00001 /* $Id$ */
00002 /*
00003 ** Copyright (C) 2002 Chris Reid <chris.reid@codecraftconsulants.com>
00004 **
00005 ** This program is free software; you can redistribute it and/or modify
00006 ** it under the terms of the GNU General Public License as published by
00007 ** the Free Software Foundation; either version 2 of the License, or
00008 ** (at your option) any later version.
00009 **
00010 ** This program is distributed in the hope that it will be useful,
00011 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
00012 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013 ** GNU General Public License for more details.
00014 **
00015 ** You should have received a copy of the GNU General Public License
00016 ** along with this program; if not, write to the Free Software
00017 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00018 */
00019 
00020 /*
00021  * win32_service.c v1.0 - 20 February 2002
00022  * 
00023  * Purpose: Lets Snort register as a Win32 Service.  This includes both
00024  *          an installation an uninstallation aspect.
00025  *
00026  * Author:  Chris Reid (chris.reid@codecraftconsulants.com)
00027  *
00028  * Notes:   The Snort command-line arguments need to be
00029  *          saved into the registry when the snort service is
00030  *          being installed.  They are stored in:
00031  *              HKLM \ SOFTWARE \ Snort
00032  *          
00033  * Usage:
00034  *          snort.exe /SERVICE /INSTALL [regular command-line params]
00035  *          
00036  *          snort.exe /SERVICE /UNINSTALL
00037  * 
00038  *          snort.exe /SERVICE /SHOW
00039  * 
00040  * References 
00041  *          Microsoft has full docs on programming Win32 Services in their
00042  *          MSDN (Microsoft Developer Network) library.
00043  *          http://msdn.microsoft.com/
00044  */
00045 
00046 #ifdef ENABLE_WIN32_SERVICE
00047 
00048 /*
00049  * Enable the next line to automatically assign a description to the Service.
00050  * According to the Microsoft documentation, the call to ChangeServiceConfig2()
00051  * which sets the description is only available on Windows 2000 or newer.
00052  *
00053  *  #define SET_SERVICE_DESCRIPTION
00054  */
00055 
00056 
00057 #ifdef HAVE_CONFIG_H
00058 #include "config.h"
00059 #endif
00060 
00061 #include <Windows.h>
00062 #include <Winsvc.h>  /* for Service stuff */
00063 #include <stdio.h>   /* for printf(), etc */
00064 #include <direct.h>  /* for _getcwd()     */
00065 
00066 #include "snort.h"
00067 #include "debug.h"
00068 #include "util.h"
00069 
00070 static LPTSTR g_lpszServiceName        = "SnortSvc";
00071 static LPTSTR g_lpszServiceDisplayName = "Snort";
00072 static LPTSTR g_lpszServiceDescription = "The Open Source Network Intrusion Detection System";
00073 
00074 static LPTSTR g_lpszRegistryKey        = "SOFTWARE\\Snort";
00075 static LPTSTR g_lpszRegistryCmdFormat  = "CmdLineParam_%03d";
00076 static LPTSTR g_lpszRegistryCountFormat= "CmdLineParamCount";
00077 
00078 static SERVICE_STATUS          g_SnortServiceStatus; 
00079 static SERVICE_STATUS_HANDLE   g_SnortServiceStatusHandle; 
00080 
00081 #define MAX_REGISTRY_KEY_LENGTH   255
00082 #define MAX_REGISTRY_DATA_LENGTH  1000
00083  
00084 
00085 static VOID  SvcDebugOut(LPSTR String, DWORD Status);
00086 static VOID  SvcFormatMessage(LPSTR szString, int iCount);
00087 static VOID  ReadServiceCommandLineParams( int * piArgCounter, char** * pargvDynamic );
00088 static VOID  WINAPI SnortServiceStart (DWORD argc, LPTSTR *argv); 
00089 static VOID  WINAPI SnortServiceCtrlHandler (DWORD opcode); 
00090 static DWORD SnortServiceInitialization (DWORD argc, LPTSTR *argv, DWORD *specificError); 
00091 static VOID  InstallSnortService(int argc, char* argv[]);
00092 static VOID  UninstallSnortService();
00093 static VOID  ShowSnortServiceParams();
00094 
00095 
00096 
00097 
00098 /*******************************************************************************
00099  * (This documentation was taken from Microsoft's own doc's on how to create
00100  * a Win32 Service.)
00101  *
00102  * Writing a Service Program's main Function
00103  * -----------------------------------------------------------------------------
00104  * 
00105  * The main function of a service program calls the StartServiceCtrlDispatcher
00106  * function to connect to the SCM and start the control dispatcher thread. The
00107  * dispatcher thread loops, waiting for incoming control requests for the
00108  * services specified in the dispatch table. This thread does not return until
00109  * there is an error or all of the services in the process have terminated. When
00110  * all services in a process have terminated, the SCM sends a control request
00111  * to the dispatcher thread telling it to shut down. The thread can then return
00112  * from the StartServiceCtrlDispatcher call and the process can terminate.
00113  * 
00114  * The following example is a service process that supports only one service. It
00115  * takes two parameters: a string that can contain one formatted output
00116  * character and a numeric value to be used as the formatted character. The
00117  * SvcDebugOut function prints informational messages and errors to the debugger.
00118  * For information on writing the SnortServiceStart and SnortServiceInitialization
00119  * functions, see Writing a ServiceMain Function. For information on writing the
00120  * SnortServiceCtrlHandler function, see Writing a Control Handler Function. 
00121  *******************************************************************************/
00122 
00123 
00124 /* this is the entry point which is called from main() */
00125 int SnortServiceMain(int argc, char* argv[]) 
00126 {
00127     int i;
00128     SERVICE_TABLE_ENTRY   steDispatchTable[] = 
00129     { 
00130         { g_lpszServiceName, SnortServiceStart }, 
00131         { NULL,       NULL                     } 
00132     }; 
00133 
00134     for( i=1; i<argc; i++ )
00135     {
00136         if( _stricmp(argv[i],SERVICE_CMDLINE_PARAM) == 0)
00137         {
00138             /* Ignore param, because we already know that this is a service
00139              * simply by the fact that we are already in this function.
00140              * However, perform a sanity check to ensure that the user
00141              * didn't just type "snort /SERVICE" without an indicator
00142              * following.
00143              */
00144 
00145             if( (i+1) < argc &&
00146                 ( _stricmp(argv[(i+1)], SERVICE_INSTALL_CMDLINE_PARAM)!=0   ||
00147                   _stricmp(argv[(i+1)], SERVICE_UNINSTALL_CMDLINE_PARAM)!=0 ||
00148                   _stricmp(argv[(i+1)], SERVICE_SHOW_CMDLINE_PARAM)!=0       ) )
00149             {
00150                 /* user entered correct command-line parameters, keep looping */
00151                 continue;
00152             }
00153         }
00154         else if( _stricmp(argv[i],SERVICE_INSTALL_CMDLINE_PARAM) == 0)
00155         {
00156             DEBUG_WRAP(DebugMessage(DEBUG_INIT, "User wishes to install the Snort service\n"););
00157             InstallSnortService(argc, argv);
00158             exit(0);
00159         }
00160         else if( _stricmp(argv[i],SERVICE_UNINSTALL_CMDLINE_PARAM) == 0)
00161         {
00162             DEBUG_WRAP(DebugMessage(DEBUG_INIT, "User wishes to un-install the Snort service\n"););
00163             UninstallSnortService();
00164             exit(0);
00165         }
00166         else if( _stricmp(argv[i],SERVICE_SHOW_CMDLINE_PARAM) == 0)
00167         {
00168             DEBUG_WRAP(DebugMessage(DEBUG_INIT, "User wishes to show the Snort service command-line parameters\n"););
00169             ShowSnortServiceParams();
00170             exit(0);
00171         }
00172         else
00173         {
00174             break;  /* out of for() */
00175         }
00176     }
00177 
00178     /* If we got to this point, then it's time to start up the Win32 Service */
00179     if (!StartServiceCtrlDispatcher(steDispatchTable)) 
00180     {
00181         char szString[1024];
00182         memset(szString, sizeof(szString), '\0');
00183         SvcFormatMessage(szString, sizeof(szString));
00184 
00185         SvcDebugOut(szString, 0); 
00186         SvcDebugOut(" [SNORT_SERVICE] StartServiceCtrlDispatcher error = %d\n%s\n", GetLastError()); 
00187         FatalError (" [SNORT_SERVICE] StartServiceCtrlDispatcher error = %d\n%s\n", GetLastError(), szString); 
00188     }
00189 
00190     return(0);
00191 } 
00192  
00193 VOID SvcDebugOut(LPSTR szString, DWORD dwStatus) 
00194 { 
00195     CHAR  szBuffer[1024]; 
00196     if (strlen(szString) < 1000) 
00197     { 
00198         sprintf(szBuffer, szString, dwStatus); 
00199         OutputDebugStringA(szBuffer); 
00200     } 
00201 }
00202 
00203 /* Copy the system error message into the buffer provided.
00204  * The buffer length is indicated in iCount.
00205  */
00206 VOID SvcFormatMessage(LPSTR szString, int iCount)
00207 {
00208     LPVOID lpMsgBuf;
00209     if( szString!=NULL && iCount>0)
00210     {
00211         memset(szString, 0, iCount);
00212         FormatMessage( FORMAT_MESSAGE_ALLOCATE_BUFFER | 
00213                        FORMAT_MESSAGE_FROM_SYSTEM | 
00214                        FORMAT_MESSAGE_IGNORE_INSERTS,
00215                        NULL,
00216                        GetLastError(),
00217                        MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
00218                        (LPTSTR) &lpMsgBuf,
00219                        0,
00220                        NULL 
00221                      );
00222 
00223         strncpy(szString, (LPCTSTR) lpMsgBuf, iCount);
00224         /* Free the buffer. */
00225         LocalFree( lpMsgBuf );
00226         lpMsgBuf = NULL;
00227     }
00228 }
00229 
00230 
00231 VOID ReadServiceCommandLineParams( int * piArgCounter, char** * pargvDynamic )
00232 {
00233     HKEY  hkSnort = NULL;
00234     long  lRegRC = 0;
00235     DWORD dwType;
00236     DWORD dwDataSize;
00237     BYTE  byData[MAX_REGISTRY_DATA_LENGTH];
00238     int   i;
00239 
00240     /**********
00241      * Read the registry entries for Snort command line parameters
00242      **********/
00243     lRegRC = RegOpenKeyEx( HKEY_LOCAL_MACHINE,        /* handle to open key      */
00244                            g_lpszRegistryKey,         /* subkey name             */
00245                            0,                         /* reserved (must be zero) */
00246                            KEY_READ,                  /* desired security access */
00247                            &hkSnort                   /* key handle              */
00248                          );
00249     if( lRegRC != ERROR_SUCCESS )
00250     {
00251         TCHAR szMsg[1000];
00252         SvcFormatMessage(szMsg, sizeof(szMsg));
00253         FatalError(" [SNORT_SERVICE] Unable to open Snort registry entry. "
00254                    " Perhaps Snort has not been installed as a service."
00255                    " %s", szMsg); 
00256     }
00257 
00258     memset(byData, 0, sizeof(byData));
00259     dwDataSize = sizeof(byData);
00260     lRegRC = RegQueryValueEx( hkSnort,                      /* handle to key       */
00261                               g_lpszRegistryCountFormat,    /* value name          */
00262                               NULL,                         /* reserved            */
00263                               &dwType,                      /* type buffer         */
00264                               byData,                       /* data buffer         */
00265                               &dwDataSize                   /* size of data buffer */
00266                             );
00267     if( lRegRC != ERROR_SUCCESS )
00268     {
00269         TCHAR szMsg[1000];
00270         SvcFormatMessage(szMsg, sizeof(szMsg));
00271         FatalError(" [SNORT_SERVICE] Unable to read Snort registry entry '%s'."
00272                    " Perhaps Snort has not been installed as a service."
00273                    " %s", g_lpszRegistryCountFormat, szMsg); 
00274     }
00275 
00276     (*piArgCounter) = * ((int*)&byData);
00277 
00278     (*pargvDynamic) = calloc( (*piArgCounter)+2, sizeof(char*) );
00279     (*pargvDynamic)[0] = _strdup(g_lpszServiceName);
00280 
00281     DEBUG_WRAP(DebugMessage(DEBUG_INIT, "Preparing to use the following command-line arguments:\n"););
00282 
00283     for( i=1; i<=(*piArgCounter); i++ )
00284     {
00285         TCHAR szName[MAX_REGISTRY_KEY_LENGTH];
00286         sprintf(szName, g_lpszRegistryCmdFormat, i);
00287         memset(byData, 0, sizeof(byData));
00288         dwDataSize = sizeof(byData);
00289         lRegRC = RegQueryValueEx( hkSnort,            /* handle to key       */
00290                                   szName,             /* value name          */
00291                                   NULL,               /* reserved            */
00292                                   &dwType,            /* type buffer         */
00293                                   byData,             /* data buffer         */
00294                                   &dwDataSize         /* size of data buffer */
00295                                 );
00296         if( lRegRC != ERROR_SUCCESS )
00297         {
00298             TCHAR szMsg[1000];
00299             SvcFormatMessage(szMsg, sizeof(szMsg));
00300             FatalError(" [SNORT_SERVICE] Unable to read Snort registry entry '%s'."
00301                        " Perhaps Snort has not been installed as a service."
00302                        " %s", szName, szMsg); 
00303         }
00304 
00305         (*pargvDynamic)[i] = _strdup( (char*) byData );
00306         DEBUG_WRAP(DebugMessage(DEBUG_INIT, "  %s\n", (*pargvDynamic)[i]););
00307     }
00308     lRegRC = RegCloseKey( hkSnort );
00309     if( lRegRC != ERROR_SUCCESS )
00310     {
00311         TCHAR szMsg[1000];
00312         SvcFormatMessage(szMsg, sizeof(szMsg));
00313         FatalError(" [SNORT_SERVICE] Unable to close Snort registry entry."
00314                    " Perhaps Snort has not been installed as a service."
00315                    " %s", szMsg); 
00316     }
00317     hkSnort = NULL;
00318 }
00319 
00320 
00321 /*******************************************************************************
00322  * (This documentation was taken from Microsoft's own doc's on how to create
00323  * a Win32 Service.)
00324  *
00325  * Writing a ServiceMain Function
00326  * -----------------------------------------------------------------------------
00327  * 
00328  * The SnortServiceStart function in the following example is the entry point for
00329  * the service. SnortServiceStart has access to the command-line arguments, in the
00330  * way that the main function of a console application does. The first parameter
00331  * contains the number of arguments being passed to the service. There will
00332  * always be at least one argument. The second parameter is a pointer to an
00333  * array of string pointers. The first item in the array always points to the
00334  * service name. 
00335  * 
00336  * The SnortServiceStart function first fills in the SERVICE_STATUS structure
00337  * including the control codes that it accepts. Although this service accepts
00338  * SERVICE_CONTROL_PAUSE and SERVICE_CONTROL_CONTINUE, it does nothing
00339  * significant when told to pause. The flags SERVICE_ACCEPT_PAUSE_CONTINUE was
00340  * included for illustration purposes only; if pausing does not add value to
00341  * your service, do not support it. 
00342  * 
00343  * The SnortServiceStart function then calls the RegisterServiceCtrlHandler
00344  * function to register SnortService as the service's Handler function and begin
00345  * initialization. The following sample initialization function,
00346  * SnortServiceInitialization, is included for illustration purposes; it does not
00347  * perform any initialization tasks such as creating additional threads. If
00348  * your service's initialization performs tasks that are expected to take longer
00349  * than one second, your code must call the SetServiceStatus function
00350  * periodically to send out wait hints and check points indicating that progress
00351  * is being made. 
00352  * 
00353  * When initialization has completed successfully, the example calls
00354  * SetServiceStatus with a status of SERVICE_RUNNING and the service continues
00355  * with its work. If an error has occurred in initialization, SnortServiceStart
00356  * reports SERVICE_STOPPED with the SetServiceStatus function and returns.
00357  * 
00358  * Because this sample service does not complete any real tasks, SnortServiceStart
00359  * simply returns control to the caller. However, your service should use this
00360  * thread to complete whatever tasks it was designed to do. If a service does not
00361  * need a thread to do its work (such as a service that only processes RPC
00362  * requests), its ServiceMain function should return control to the caller. It is
00363  * important for the function to return, rather than call the ExitThread
00364  * function, because returning allows for cleanup of the memory allocated for the
00365  * arguments.
00366  * 
00367  * To output debugging information, SnortServiceStart calls SvcDebugOut. The source
00368  * code for SvcDebugOut is given in Writing a Service Program's main Function. 
00369  *******************************************************************************/
00370 
00371 void logmsg(char* msg)
00372 {
00373     FILE *pFile;
00374     if( (pFile=fopen("c:\\snortlog.txt", "a")) != NULL )
00375     {
00376         if( msg != NULL )
00377         {
00378             fprintf(pFile, msg);
00379         }
00380         else
00381         {
00382             fprintf(pFile, "Message String is NULL\n");
00383         }
00384         fclose(pFile);
00385         pFile = NULL;
00386     }
00387 }
00388 
00389 void logadapternames( char* interfacenames, char* errorbuf )
00390 {
00391     char AdaptersName[8192];
00392     int i;
00393     memset(AdaptersName, 0x00, sizeof(AdaptersName));
00394     for( i=0; i<sizeof(AdaptersName); i+=2 )
00395     {
00396         AdaptersName[i/2] = interfacenames[i];
00397     }
00398     for( i=0; i<sizeof(AdaptersName)-1; i++ )
00399     {
00400         if( AdaptersName[i] == 0x00 && AdaptersName[i+1] != 0x00 )
00401         {
00402             AdaptersName[i] = '\n';
00403         }
00404     }
00405     logmsg("Errorbuf:");
00406     logmsg(errorbuf);
00407     logmsg("\nAdaptersName:");
00408     logmsg(AdaptersName);
00409     logmsg("\n");
00410 }
00411 
00412 void WINAPI SnortServiceStart (DWORD argc, LPTSTR *argv) 
00413 { 
00414     int i;
00415     int iArgCounter;
00416     char** argvDynamic = NULL;
00417     char errorbuf[PCAP_ERRBUF_SIZE];
00418     char *interfacenames = NULL;
00419 
00420     DWORD dwStatus; 
00421     DWORD dwSpecificError; 
00422 
00423     g_SnortServiceStatus.dwServiceType             = SERVICE_WIN32; 
00424     g_SnortServiceStatus.dwCurrentState            = SERVICE_START_PENDING; 
00425     g_SnortServiceStatus.dwControlsAccepted        = SERVICE_ACCEPT_STOP | SERVICE_ACCEPT_PAUSE_CONTINUE; 
00426     g_SnortServiceStatus.dwWin32ExitCode           = 0; 
00427     g_SnortServiceStatus.dwServiceSpecificExitCode = 0; 
00428     g_SnortServiceStatus.dwCheckPoint              = 0; 
00429     g_SnortServiceStatus.dwWaitHint                = 0; 
00430  
00431     g_SnortServiceStatusHandle = RegisterServiceCtrlHandler(g_lpszServiceName, SnortServiceCtrlHandler); 
00432  
00433     if (g_SnortServiceStatusHandle == (SERVICE_STATUS_HANDLE)0) 
00434     { 
00435         TCHAR szMsg[1000];
00436         SvcFormatMessage(szMsg, sizeof(szMsg));
00437         SvcDebugOut(" [SNORT_SERVICE] RegisterServiceCtrlHandler failed %d\n", GetLastError()); 
00438         FatalError (" [SNORT_SERVICE] RegisterServiceCtrlHandler failed %d\n%s\n", GetLastError(), szMsg); 
00439         return; 
00440     } 
00441  
00442     /* Initialization code goes here. */
00443     dwStatus = SnortServiceInitialization(argc, argv, &dwSpecificError); 
00444  
00445     /* Handle error condition */
00446     if (dwStatus != NO_ERROR) 
00447     { 
00448         g_SnortServiceStatus.dwCurrentState            = SERVICE_STOPPED; 
00449         g_SnortServiceStatus.dwCheckPoint              = 0; 
00450         g_SnortServiceStatus.dwWaitHint                = 0; 
00451         g_SnortServiceStatus.dwWin32ExitCode           = dwStatus; 
00452         g_SnortServiceStatus.dwServiceSpecificExitCode = dwSpecificError; 
00453  
00454         SetServiceStatus (g_SnortServiceStatusHandle, &g_SnortServiceStatus); 
00455         return; 
00456     } 
00457  
00458     /* Initialization complete - report running status. */
00459     g_SnortServiceStatus.dwCurrentState       = SERVICE_RUNNING; 
00460     g_SnortServiceStatus.dwCheckPoint         = 0; 
00461     g_SnortServiceStatus.dwWaitHint           = 0; 
00462  
00463     if (!SetServiceStatus (g_SnortServiceStatusHandle, &g_SnortServiceStatus)) 
00464     { 
00465         TCHAR szMsg[1000];
00466         SvcFormatMessage(szMsg, sizeof(szMsg));
00467         dwStatus = GetLastError(); 
00468         SvcDebugOut(" [SNORT_SERVICE] SetServiceStatus error %ld\n",dwStatus); 
00469         FatalError (" [SNORT_SERVICE] SetServiceStatus error %ld\n%s\n",dwStatus,szMsg); 
00470     } 
00471 
00472     /* There seems to be a bug in Winpcap, such that snort works fine
00473      * when it is started from the command line, and the service works
00474      * fine if a user has run "snort -W" already.  However the service
00475      * fails to start (on some machines only) if snort hasn't been
00476      * run manually first.  So here we simulate a user having run
00477      * "snort -W", then let it go on its merry way.
00478      */
00479     memset( errorbuf, '\0', sizeof(errorbuf) );
00480     interfacenames = pcap_lookupdev(errorbuf);
00481     logadapternames( interfacenames, errorbuf );
00482     
00483     /* This is where the service does its work. */
00484     ReadServiceCommandLineParams( &iArgCounter, &argvDynamic );
00485     SnortMain( iArgCounter+1, argvDynamic );
00486 
00487     /* Cleanup now */
00488     for( i=0; i<=iArgCounter; i++ )
00489     {
00490         free( argvDynamic[i] );
00491         argvDynamic[i] = NULL;
00492     }
00493     free( argvDynamic );
00494     argvDynamic = NULL;
00495 
00496     SvcDebugOut(" [SNORT_SERVICE] Returning the Main Thread \n",0); 
00497  
00498     return; 
00499 } 
00500  
00501 /* Stub initialization function. */
00502 DWORD SnortServiceInitialization(DWORD argc, LPTSTR *argv, DWORD *pdwSpecificError) 
00503 { 
00504     argv; 
00505     argc; 
00506     pdwSpecificError; 
00507     return(0); 
00508 } 
00509 
00510 
00511 
00512 /*******************************************************************************
00513  * (This documentation was taken from Microsoft's own doc's on how to create
00514  * a Win32 Service.)
00515  *
00516  * Writing a Control Handler Function
00517  * -----------------------------------------------------------------------------
00518  * 
00519  * The SnortServiceCtrlHandler function in the following example is the Handler
00520  * function. When this function is called by the dispatcher thread, it handles
00521  * the control code passed in the Opcode parameter and then calls the
00522  * SetServiceStatus function to update the service's status. Every time a
00523  * Handler function receives a control code, it is appropriate to return status
00524  * with a call to SetServiceStatus regardless of whether the service acts on
00525  * the control.
00526  * 
00527  * When the pause control is received, SnortServiceCtrlHandler simply sets the
00528  * dwCurrentState field in the SERVICE_STATUS structure to SERVICE_PAUSED.
00529  * Likewise, when the continue control is received, the state is set to
00530  * SERVICE_RUNNING. Therefore, SnortServiceCtrlHandler is not a good example of
00531  * how to handle the pause and continue controls. Because SnortServiceCtrlHandler
00532  * is a template for a Handler function, code for the pause and continue
00533  * controls is included for completeness. A service that supports either the
00534  * pause or continue control should handle these controls in a way that makes
00535  * sense. Many services support neither the pause or continue control. If the
00536  * service indicates that it does not support pause or continue with the
00537  * dwControlsAccepted parameter, then the SCM will not send pause or continue
00538  * controls to the service's Handler function. 
00539  * 
00540  * To output debugging information, SnortServiceCtrlHandler calls SvcDebugOut. The
00541  * source code for SvcDebugOut is listed in Writing a Service Program's main
00542  * Function. Also, note that the g_SnortServiceStatus variable is a global variable
00543  * and should be initialized as demonstrated in Writing a ServiceMain function. 
00544  *******************************************************************************/
00545 
00546 VOID WINAPI SnortServiceCtrlHandler (DWORD dwOpcode) 
00547 { 
00548     DWORD dwStatus; 
00549  
00550     switch(dwOpcode) 
00551     { 
00552         case SERVICE_CONTROL_PAUSE: 
00553             /* Do whatever it takes to pause here.  */
00554             pv.pause_service_flag = 1;
00555 
00556             g_SnortServiceStatus.dwCurrentState = SERVICE_PAUSED; 
00557             break; 
00558  
00559         case SERVICE_CONTROL_CONTINUE: 
00560             /* Do whatever it takes to continue here.  */
00561             pv.pause_service_flag = 0;
00562 
00563             g_SnortServiceStatus.dwCurrentState = SERVICE_RUNNING; 
00564             break; 
00565  
00566         case SERVICE_CONTROL_STOP: 
00567             /* Do whatever it takes to stop here. */
00568             pv.terminate_service_flag = 1;
00569 
00570             Sleep( READ_TIMEOUT * 2 );  /* wait for 2x the timeout, just to ensure that things
00571                                          * the service has processed any last packets
00572                                          */
00573 
00574             g_SnortServiceStatus.dwWin32ExitCode = 0; 
00575             g_SnortServiceStatus.dwCurrentState  = SERVICE_STOPPED; 
00576             g_SnortServiceStatus.dwCheckPoint    = 0; 
00577             g_SnortServiceStatus.dwWaitHint      = 0; 
00578  
00579             if (!SetServiceStatus (g_SnortServiceStatusHandle, &g_SnortServiceStatus))
00580             { 
00581                 dwStatus = GetLastError(); 
00582                 SvcDebugOut(" [SNORT_SERVICE] SetServiceStatus error %ld\n",dwStatus); 
00583             } 
00584  
00585             SvcDebugOut(" [SNORT_SERVICE] Leaving SnortService \n",0); 
00586             return; 
00587  
00588         case SERVICE_CONTROL_INTERROGATE: 
00589             /* Fall through to send current status. */
00590             break; 
00591  
00592         default: 
00593             SvcDebugOut(" [SNORT_SERVICE] Unrecognized opcode %ld\n", dwOpcode); 
00594     } 
00595  
00596     /* Send current status.  */
00597     if (!SetServiceStatus (g_SnortServiceStatusHandle,  &g_SnortServiceStatus)) 
00598     { 
00599         dwStatus = GetLastError(); 
00600         SvcDebugOut(" [SNORT_SERVICE] SetServiceStatus error %ld\n",dwStatus); 
00601     } 
00602 
00603     return; 
00604 } 
00605 
00606 
00607 
00608 /*******************************************************************************
00609  * (This documentation was taken from Microsoft's own doc's on how to create
00610  * a Win32 Service.)
00611  *
00612  * Installing a Service
00613  * -----------------------------------------------------------------------------
00614  * 
00615  * A service configuration program uses the CreateService function to install a
00616  * service in a SCM database. The application-defined schSCManager handle must
00617  * have SC_MANAGER_CREATE_SERVICE access to the SCManager object. The following
00618  * example shows how to install a service. 
00619  *******************************************************************************/
00620 
00621 VOID InstallSnortService(int argc, char* argv[]) 
00622 { 
00623     SC_HANDLE schSCManager, schService;
00624     char buffer[_MAX_PATH+1];
00625     LPCTSTR lpszBinaryPathName = NULL;
00626     HKEY hkSnort = NULL;
00627     long lRegRC = 0;
00628     int iArgCounter;
00629     DWORD dwWriteCounter = 0;
00630 #ifdef SET_SERVICE_DESCRIPTION
00631     SERVICE_DESCRIPTION sdBuf;
00632 #endif
00633 
00634 
00635     printf("\n\n");
00636     printf(" [SNORT_SERVICE] Attempting to install the Snort service.\n");
00637 
00638     /**********
00639      * Build up a string which stores the full path to the Snort executable.
00640      * This takes into account the current working directory, along with a
00641      * relative path to the Snort executable.
00642      **********/
00643     memset( buffer, 0, sizeof(buffer) );
00644     if( _getcwd( buffer, _MAX_PATH ) == NULL )
00645     {
00646         TCHAR szMsg[1000];
00647         SvcFormatMessage(szMsg, sizeof(szMsg));
00648         FatalError(" [SNORT_SERVICE] Unable to determine current working directory. %s", szMsg); 
00649     }
00650     if( buffer[strlen(buffer)-1] != '\\' )
00651     {
00652         strcat(buffer, "\\");
00653     }
00654     strcat(buffer, argv[0]);
00655     strcat(buffer, " ");
00656     strcat(buffer, SERVICE_CMDLINE_PARAM);
00657     lpszBinaryPathName = buffer;
00658 
00659     printf("\n");
00660     printf(" [SNORT_SERVICE] The full path to the Snort binary appears to be:\n");
00661     printf("    %s\n", lpszBinaryPathName);
00662 
00663 
00664 
00665     /**********
00666      * Create the registry entries for Snort command line parameters
00667      **********/
00668     lRegRC = RegCreateKeyEx( HKEY_LOCAL_MACHINE,        /* handle to open key       */
00669                              g_lpszRegistryKey,         /* subkey name              */
00670                              0,                         /* reserved (must be zero)  */
00671                              NULL,                      /* class string             */
00672                              REG_OPTION_NON_VOLATILE,   /* special options          */
00673                              KEY_ALL_ACCESS,            /* desired security access  */
00674                              NULL,                      /* inheritance              */
00675                              &hkSnort,                  /* key handle               */
00676                              NULL                       /* disposition value buffer */
00677                            );
00678     if( lRegRC != ERROR_SUCCESS )
00679     {
00680         TCHAR szMsg[1000];
00681         SvcFormatMessage(szMsg, sizeof(szMsg));
00682         FatalError(" [SNORT_SERVICE] Unable to create Snort registry entry. %s", szMsg); 
00683     }
00684 
00685     for( iArgCounter=1; iArgCounter<argc; iArgCounter++ )
00686     {
00687         /* ignore the Service command line parameters (/SERVICE, /INSTALL, /UNINSTALL)
00688          * and store all others in the registry
00689          */
00690         if( ( _stricmp(argv[iArgCounter],SERVICE_CMDLINE_PARAM)           == 0 )  ||
00691             ( _stricmp(argv[iArgCounter],SERVICE_INSTALL_CMDLINE_PARAM)   == 0 )  ||
00692             ( _stricmp(argv[iArgCounter],SERVICE_UNINSTALL_CMDLINE_PARAM) == 0 )   )
00693         {
00694             /* ignore it, because it isn't a real Snort command-line parameter */
00695         }
00696         else if( strlen(argv[iArgCounter]) > MAX_REGISTRY_DATA_LENGTH )
00697         {
00698             FatalError(" [SNORT_SERVICE] A single command line parameter cannot exceed %d characters.", MAX_REGISTRY_DATA_LENGTH); 
00699         }
00700         else
00701         {
00702             char szSubkeyName[30];
00703             dwWriteCounter++;
00704             sprintf(szSubkeyName, g_lpszRegistryCmdFormat, dwWriteCounter);
00705             lRegRC = RegSetValueEx( hkSnort,                       /* handle to key to set value for */
00706                                     szSubkeyName,                  /* name of the value to set       */
00707                                     0,                             /* reserved                       */
00708                                     REG_SZ,                        /* flag for value type            */
00709                                     (LPBYTE) argv[iArgCounter],    /* address of value data          */
00710                                     strlen(argv[iArgCounter])      /* size of value data             */
00711                                   );
00712             if( lRegRC != ERROR_SUCCESS )
00713             {
00714                 TCHAR szMsg[1000];
00715                 SvcFormatMessage(szMsg, sizeof(szMsg));
00716                 FatalError(" [SNORT_SERVICE] Unable to write Snort registry entry. %s", szMsg); 
00717             }
00718         }
00719     } /* end for() */
00720 
00721     lRegRC = RegSetValueEx( hkSnort,                       /* handle to key to set value for */
00722                             g_lpszRegistryCountFormat,     /* name of the value to set       */
00723                             0,                             /* reserved                       */
00724                             REG_DWORD,                     /* flag for value type            */
00725                             (LPBYTE) &dwWriteCounter,      /* address of value data          */
00726                             sizeof(dwWriteCounter)         /* size of value data             */
00727                           );
00728     if( lRegRC != ERROR_SUCCESS )
00729     {
00730         TCHAR szMsg[1000];
00731         SvcFormatMessage(szMsg, sizeof(szMsg));
00732         FatalError(" [SNORT_SERVICE] Unable to write Snort registry entry. %s", szMsg); 
00733     }
00734 
00735     lRegRC = RegCloseKey( hkSnort );
00736     if( lRegRC != ERROR_SUCCESS )
00737     {
00738         TCHAR szMsg[1000];
00739         SvcFormatMessage(szMsg, sizeof(szMsg));
00740         FatalError(" [SNORT_SERVICE] Unable to close Snort registry entry. %s", szMsg); 
00741     }
00742 
00743     printf("\n");
00744     printf(" [SNORT_SERVICE] Successfully added registry keys to:\n");
00745     printf("    \\HKEY_LOCAL_MACHINE\\%s\\\n", g_lpszRegistryKey);
00746 
00747 
00748     /**********
00749      * Add Snort to the Services database
00750      **********/
00751     schSCManager = OpenSCManager(NULL,                    /* local machine                        */
00752                                  NULL,                    /* defaults to SERVICES_ACTIVE_DATABASE */
00753                                  SC_MANAGER_ALL_ACCESS);  /* full access rights                   */
00754  
00755     if (schSCManager == NULL)
00756     {
00757         DWORD dwErr = GetLastError();
00758         LPCTSTR lpszBasicMessage = "Unable to open a connection to the Services database."; 
00759         TCHAR szMsg[1000];
00760 
00761         SvcFormatMessage(szMsg, sizeof(szMsg));
00762         switch(dwErr)
00763         {
00764         case ERROR_ACCESS_DENIED: 
00765             FatalError(" [SNORT_SERVICE] %s Access is denied. %s", lpszBasicMessage, szMsg);
00766             break;
00767 
00768         case ERROR_DATABASE_DOES_NOT_EXIST: 
00769             FatalError(" [SNORT_SERVICE] %s Services database does not exist. %s", lpszBasicMessage, szMsg);
00770             break;
00771 
00772         case ERROR_INVALID_PARAMETER: 
00773             FatalError(" [SNORT_SERVICE] %s Invalid parameter. %s", lpszBasicMessage, szMsg);
00774             break;
00775 
00776         default: 
00777             FatalError(" [SNORT_SERVICE] %s Unrecognized error (%d). %s", lpszBasicMessage, dwErr, szMsg);
00778             break;
00779         }
00780     }
00781 
00782     schService = CreateService( schSCManager,              /* SCManager database        */
00783                                 g_lpszServiceName,         /* name of service           */
00784                                 g_lpszServiceDisplayName,  /* service name to display   */
00785                                 SERVICE_ALL_ACCESS,        /* desired access            */
00786                                 SERVICE_WIN32_OWN_PROCESS, /* service type              */
00787                                 SERVICE_DEMAND_START,      /* start type                */
00788                                 SERVICE_ERROR_NORMAL,      /* error control type        */
00789                                 lpszBinaryPathName,        /* service's binary          */
00790                                 NULL,                      /* no load ordering group    */
00791                                 NULL,                      /* no tag identifier         */
00792                                 NULL,                      /* no dependencies           */
00793                                 NULL,                      /* LocalSystem account       */
00794                                 NULL);                     /* no password               */
00795  
00796     if (schService == NULL)
00797     {
00798         DWORD dwErr = GetLastError();
00799         LPCTSTR lpszBasicMessage = "Error while adding the Snort service to the Services database."; 
00800         TCHAR szMsg[1000];
00801 
00802         SvcFormatMessage(szMsg, sizeof(szMsg));
00803         switch(dwErr)
00804         {
00805         case ERROR_ACCESS_DENIED: 
00806             FatalError(" [SNORT_SERVICE] %s Access is denied. %s", lpszBasicMessage, szMsg);
00807             break;
00808         case ERROR_CIRCULAR_DEPENDENCY:
00809             FatalError(" [SNORT_SERVICE] %s Circular dependency. %s", lpszBasicMessage, szMsg);
00810             break;
00811 
00812         case ERROR_DUP_NAME: 
00813             FatalError(" [SNORT_SERVICE] %s The display name (\"%s\") is already in use. %s", lpszBasicMessage
00814                                                                                             , g_lpszServiceDisplayName
00815                                                                                             , szMsg);
00816             break;
00817 
00818         case ERROR_INVALID_HANDLE: 
00819             FatalError(" [SNORT_SERVICE] %s Invalid handle. %s", lpszBasicMessage, szMsg);
00820             break;
00821 
00822         case ERROR_INVALID_NAME: 
00823             FatalError(" [SNORT_SERVICE] %s Invalid service name. %s", lpszBasicMessage, szMsg);
00824             break;
00825 
00826         case ERROR_INVALID_PARAMETER: 
00827             FatalError(" [SNORT_SERVICE] %s Invalid parameter. %s", lpszBasicMessage, szMsg);
00828             break;
00829 
00830         case ERROR_INVALID_SERVICE_ACCOUNT: 
00831             FatalError(" [SNORT_SERVICE] %s Invalid service account. %s", lpszBasicMessage, szMsg);
00832             break;
00833 
00834         case ERROR_SERVICE_EXISTS: 
00835             FatalError(" [SNORT_SERVICE] %s Service already exists. %s", lpszBasicMessage, szMsg);
00836             break;
00837 
00838         default: 
00839             FatalError(" [SNORT_SERVICE] %s Unrecognized error (%d). %s", lpszBasicMessage, dwErr, szMsg);
00840             break;
00841         }
00842     }
00843 
00844 #ifdef SET_SERVICE_DESCRIPTION
00845     /* Apparently, the call to ChangeServiceConfig2() only works on Windows >= 2000 */
00846     sdBuf.lpDescription = g_lpszServiceDescription;
00847     if( !ChangeServiceConfig2(schService,                 /* handle to service      */
00848                               SERVICE_CONFIG_DESCRIPTION, /* change: description    */
00849                               &sdBuf) )                   /* value: new description */
00850     {
00851         TCHAR szMsg[1000];
00852         SvcFormatMessage(szMsg, sizeof(szMsg));
00853         FatalError(" [SNORT_SERVICE] Unable to add a description to the Snort service. %s", szMsg); 
00854     }
00855 #endif
00856 
00857     printf("\n");
00858     printf(" [SNORT_SERVICE] Successfully added the Snort service to the Services database.\n"); 
00859  
00860     CloseServiceHandle(schService); 
00861     CloseServiceHandle(schSCManager);
00862 } 
00863 
00864 
00865 
00866 /*******************************************************************************
00867  * (This documentation was taken from Microsoft's own doc's on how to create
00868  * a Win32 Service.)
00869  *
00870  * Deleting a Service
00871  * -----------------------------------------------------------------------------
00872  * 
00873  * In the following example, a service configuration program uses the
00874  * OpenService function to get a handle with DELETE access to an installed
00875  * service object. The program then uses the service object handle in the
00876  * DeleteService function to remove the service from the SCM database. 
00877  *******************************************************************************/
00878 
00879 VOID UninstallSnortService() 
00880 { 
00881     SC_HANDLE schSCManager, schService;
00882     HKEY hkSnort = NULL;
00883     long lRegRC = 0;
00884 
00885     printf("\n\n");
00886     printf(" [SNORT_SERVICE] Attempting to uninstall the Snort service.\n");
00887 
00888 
00889     /**********
00890      * Removing the registry entries for Snort command line parameters
00891      **********/
00892     lRegRC = RegDeleteKey( HKEY_LOCAL_MACHINE,  /* handle to open key */
00893                            g_lpszRegistryKey    /* subkey name        */
00894                          );
00895     if( lRegRC != ERROR_SUCCESS )
00896     {
00897         TCHAR szMsg[1000];
00898         SvcFormatMessage(szMsg, sizeof(szMsg));
00899         printf(" [SNORT_SERVICE] Warning.  Unable to remove root Snort registry entry. %s", szMsg); 
00900     }
00901 
00902     printf("\n");
00903     printf(" [SNORT_SERVICE] Successfully removed registry keys from:\n");
00904     printf("    \\HKEY_LOCAL_MACHINE\\%s\\\n", g_lpszRegistryKey);
00905 
00906 
00907     /**********
00908      * Remove Snort from the Services database
00909      **********/
00910     schSCManager = OpenSCManager(NULL,                    /* local machine            */
00911                                  NULL,                    /* ServicesActive database  */
00912                                  SC_MANAGER_ALL_ACCESS);  /* full access rights       */
00913  
00914     if (schSCManager == NULL) 
00915     {
00916         DWORD dwErr = GetLastError();
00917         LPCTSTR lpszBasicMessage = "Unable to open a connection to the Services database."; 
00918         TCHAR szMsg[1000];
00919 
00920         SvcFormatMessage(szMsg, sizeof(szMsg));
00921         switch(dwErr)
00922         {
00923         case ERROR_ACCESS_DENIED: 
00924             FatalError(" [SNORT_SERVICE] %s Access is denied. %s", lpszBasicMessage, szMsg);
00925             break;
00926 
00927         case ERROR_DATABASE_DOES_NOT_EXIST: 
00928             FatalError(" [SNORT_SERVICE] %s Services database does not exist. %s", lpszBasicMessage, szMsg);
00929             break;
00930 
00931         case ERROR_INVALID_PARAMETER: 
00932             FatalError(" [SNORT_SERVICE] %s Invalid parameter. %s", lpszBasicMessage, szMsg);
00933             break;
00934 
00935         default: 
00936             FatalError(" [SNORT_SERVICE] %s Unrecognized error (%d). %s", lpszBasicMessage, dwErr, szMsg);
00937             break;
00938         }
00939     }
00940 
00941     schService = OpenService(schSCManager,       /* SCManager database       */
00942                              g_lpszServiceName,  /* name of service          */
00943                              DELETE);            /* only need DELETE access  */
00944  
00945     if (schService == NULL) 
00946     {
00947         DWORD dwErr = GetLastError();
00948         LPCTSTR lpszBasicMessage = "Unable to locate Snort in the Services database."; 
00949         TCHAR szMsg[1000];
00950 
00951         SvcFormatMessage(szMsg, sizeof(szMsg));
00952         switch(dwErr)
00953         {
00954         case ERROR_ACCESS_DENIED: 
00955             FatalError(" [SNORT_SERVICE] %s Access is denied. %s", lpszBasicMessage, szMsg);
00956             break;
00957 
00958         case ERROR_INVALID_HANDLE: 
00959             FatalError(" [SNORT_SERVICE] %s Invalid handle. %s", lpszBasicMessage, szMsg);
00960             break;
00961 
00962         case ERROR_INVALID_NAME: 
00963             FatalError(" [SNORT_SERVICE] %s Invalid name. %s", lpszBasicMessage, szMsg);
00964             break;
00965 
00966         case ERROR_SERVICE_DOES_NOT_EXIST: 
00967             FatalError(" [SNORT_SERVICE] %s Service does not exist. %s", lpszBasicMessage, szMsg);
00968             break;
00969 
00970         default: 
00971             FatalError(" [SNORT_SERVICE] %s Unrecognized error (%d). %s", lpszBasicMessage, dwErr, szMsg);
00972             break;
00973         }
00974     }
00975  
00976     if (! DeleteService(schService) ) 
00977     {
00978         DWORD dwErr = GetLastError();
00979         LPCTSTR lpszBasicMessage = "Unable to remove Snort from the Services database."; 
00980         TCHAR szMsg[1000];
00981 
00982         SvcFormatMessage(szMsg, sizeof(szMsg));
00983         switch(dwErr)
00984         {
00985         case ERROR_ACCESS_DENIED: 
00986             FatalError(" [SNORT_SERVICE] %s Access is denied. %s", lpszBasicMessage, szMsg);
00987             break;
00988 
00989         case ERROR_INVALID_HANDLE: 
00990             FatalError(" [SNORT_SERVICE] %s Invalid handle. %s", lpszBasicMessage, szMsg);
00991             break;
00992 
00993         case ERROR_SERVICE_MARKED_FOR_DELETE: 
00994             FatalError(" [SNORT_SERVICE] %s Service already marked for delete. %s", lpszBasicMessage, szMsg);
00995             break;
00996 
00997         default: 
00998             FatalError(" [SNORT_SERVICE] %s Unrecognized error (%d). %s", lpszBasicMessage, dwErr, szMsg);
00999             break;
01000         }
01001     }
01002 
01003     printf("\n");
01004     printf(" [SNORT_SERVICE] Successfully removed the Snort service from the Services database.\n"); 
01005  
01006     CloseServiceHandle(schService); 
01007     CloseServiceHandle(schSCManager);
01008 } 
01009 
01010 
01011 VOID  ShowSnortServiceParams()
01012 {
01013     int     argc;
01014     char ** argv;
01015     int i;
01016 
01017     ReadServiceCommandLineParams( &argc, &argv );
01018 
01019     printf("\n"
01020            "Snort is currently configured to run as a Windows service using the following\n"
01021            "command-line parameters:\n\n"
01022            "    ");
01023 
01024     for( i=1; i<=argc; i++ )
01025     {
01026         if( argv[i] != NULL )
01027         {
01028             printf(" %s", argv[i]);
01029             free( argv[i] );
01030             argv[i] = NULL;
01031         }
01032     }
01033 
01034     free( argv );
01035     argv = NULL;
01036 
01037     printf("\n");
01038 }
01039 
01040 
01041 #endif  /* ENABLE_WIN32_SERVICE */
01042 

Generated on Sun May 14 14:51:19 2006 by  doxygen 1.4.2