diff --git a/pandora_agents/win32/ChangeLog b/pandora_agents/win32/ChangeLog index 29edbd8409..4aab0a7667 100644 --- a/pandora_agents/win32/ChangeLog +++ b/pandora_agents/win32/ChangeLog @@ -1,3 +1,24 @@ +2008-12-03 Esteban Sanchez + + * pandora.[cc,h]: Function is_enabled() was moved here to be + accesible. + + * pandora_windows_service.cc: Removed is_enabled() private function. + + * windows_service.cc: Service is now interactive, so it can open + interactive processes in the watchdog mode of proc modules. + + * modules/pandora_module_factory.cc: Added "module_watchdog" and + "module_start_command" tokens to service and process modules. Style + correction. + + * modules/pandora_module_proc.[cc,h]: Added watchdog mode to run + proccess when they die. It's done by setting a start command to + recover it. + + * modules/pandora_module_service.[cc,h]: Added watchdog mode to start + a service when it's stopped. + 2008-12-01 Ramon Novoa * windows/pandora_wmi.cc, diff --git a/pandora_agents/win32/modules/pandora_module.h b/pandora_agents/win32/modules/pandora_module.h index 03f42d9346..9de043848c 100644 --- a/pandora_agents/win32/modules/pandora_module.h +++ b/pandora_agents/win32/modules/pandora_module.h @@ -101,9 +101,8 @@ namespace Pandora_Modules { * The module does not satisfy its interval. */ class Interval_Not_Fulfilled : public Pandora_Modules::Module_Exception { }; - - /** - * Pandora module super-class. + + /** * Pandora module super-class. * * Every defined module must inherit of this class. */ diff --git a/pandora_agents/win32/modules/pandora_module_factory.cc b/pandora_agents/win32/modules/pandora_module_factory.cc index 66f2fdb157..fd847f2629 100644 --- a/pandora_agents/win32/modules/pandora_module_factory.cc +++ b/pandora_agents/win32/modules/pandora_module_factory.cc @@ -35,26 +35,28 @@ using namespace Pandora; using namespace Pandora_Modules; using namespace Pandora_Strutils; -#define TOKEN_NAME ("module_name ") -#define TOKEN_TYPE ("module_type ") -#define TOKEN_INTERVAL ("module_interval ") -#define TOKEN_EXEC ("module_exec ") -#define TOKEN_PROC ("module_proc ") -#define TOKEN_SERVICE ("module_service ") -#define TOKEN_FREEDISK ("module_freedisk ") -#define TOKEN_FREEMEMORY ("module_freememory") -#define TOKEN_CPUUSAGE ("module_cpuusage ") -#define TOKEN_ODBC ("module_odbc ") -#define TOKEN_MAX ("module_max ") -#define TOKEN_MIN ("module_min ") -#define TOKEN_DESCRIPTION ("module_description ") -#define TOKEN_ODBC_QUERY ("module_odbc_query ") -#define TOKEN_LOGEVENT ("module_logevent") -#define TOKEN_SOURCE ("module_source ") -#define TOKEN_EVENTTYPE ("module_eventtype ") -#define TOKEN_EVENTCODE ("module_eventcode ") -#define TOKEN_PATTERN ("module_pattern ") -#define TOKEN_ASYNC ("module_async") +#define TOKEN_NAME ("module_name ") +#define TOKEN_TYPE ("module_type ") +#define TOKEN_INTERVAL ("module_interval ") +#define TOKEN_EXEC ("module_exec ") +#define TOKEN_PROC ("module_proc ") +#define TOKEN_SERVICE ("module_service ") +#define TOKEN_FREEDISK ("module_freedisk ") +#define TOKEN_FREEMEMORY ("module_freememory") +#define TOKEN_CPUUSAGE ("module_cpuusage ") +#define TOKEN_ODBC ("module_odbc ") +#define TOKEN_MAX ("module_max ") +#define TOKEN_MIN ("module_min ") +#define TOKEN_DESCRIPTION ("module_description ") +#define TOKEN_ODBC_QUERY ("module_odbc_query ") +#define TOKEN_LOGEVENT ("module_logevent") +#define TOKEN_SOURCE ("module_source ") +#define TOKEN_EVENTTYPE ("module_eventtype ") +#define TOKEN_EVENTCODE ("module_eventcode ") +#define TOKEN_PATTERN ("module_pattern ") +#define TOKEN_ASYNC ("module_async") +#define TOKEN_WATCHDOG ("module_watchdog ") +#define TOKEN_START_COMMAND ("module_start_command ") string parseLine (string line, string token) { @@ -90,28 +92,32 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { string module_freedisk, module_cpuusage, module_odbc; string module_odbc_query, module_dsn, module_freememory; string module_logevent, module_source, module_eventtype, module_eventcode; - string module_pattern, module_async; + string module_pattern, module_async; + string module_watchdog, module_start_command; Pandora_Module *module; bool numeric; Module_Type type; - - module_name = ""; - module_type = ""; - module_min = ""; - module_max = ""; - module_description = ""; - module_interval = ""; - module_exec = ""; - module_proc = ""; - module_service = ""; - module_odbc = ""; - module_odbc_query = ""; - module_odbc = ""; - module_logevent = ""; - module_source = ""; - module_eventtype = ""; + + module_name = ""; + module_type = ""; + module_min = ""; + module_max = ""; + module_description = ""; + module_interval = ""; + module_exec = ""; + module_proc = ""; + module_service = ""; + module_odbc = ""; + module_odbc_query = ""; + module_odbc = ""; + module_logevent = ""; + module_source = ""; + module_eventtype = ""; module_eventcode = ""; - module_pattern = ""; + module_pattern = ""; + module_async = ""; + module_watchdog = ""; + module_start_command = ""; stringtok (tokens, definition, "\n"); @@ -182,6 +188,12 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { if (module_async == "") { module_async = parseLine (line, TOKEN_ASYNC); } + if (module_start_command == "") { + module_start_command = parseLine (line, TOKEN_START_COMMAND); + } + if (module_watchdog == "") { + module_watchdog = parseLine (line, TOKEN_WATCHDOG); + } iter++; } @@ -192,10 +204,36 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { module_exec); } else if (module_proc != "") { module = new Pandora_Module_Proc (module_name, - module_proc); + module_proc); + if (module_watchdog != "") { + bool enabled; + + enabled = is_enabled (module_watchdog); + if (enabled) { + if (module_start_command == "") { + pandoraLog ("Module \"%s\" is marked to be watchdog but no recover command was set. " + "Please add a new token 'module_start_command c:\\command_to_recover.exe'", + module_name.c_str ()); + delete module; + return NULL; + } + + Pandora_Module_Proc *module_proc; + + module_proc = (Pandora_Module_Proc *) module; + module_proc->setWatchdog (true); + module_proc->setStartCommand (module_start_command); + } + } } else if (module_service != "") { module = new Pandora_Module_Service (module_name, - module_service); + module_service); + if (module_watchdog != "") { + Pandora_Module_Service *module_service; + + module_service = (Pandora_Module_Service *) module; + module_service->setWatchdog (is_enabled (module_watchdog)); + } } else if (module_freedisk != "") { module = new Pandora_Module_Freedisk (module_name, module_freedisk); @@ -221,10 +259,10 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { module_odbc_query); } else if (module_logevent != "") { module = new Pandora_Module_Logevent (module_name, - module_source, - module_eventtype, - module_eventcode, - module_pattern); + module_source, + module_eventtype, + module_eventcode, + module_pattern); } else { return NULL; } @@ -296,6 +334,7 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) { module_interval.c_str (), module_name.c_str ()); } - } + } + return module; } diff --git a/pandora_agents/win32/modules/pandora_module_proc.cc b/pandora_agents/win32/modules/pandora_module_proc.cc index 983d40d13d..a9c71e4148 100644 --- a/pandora_agents/win32/modules/pandora_module_proc.cc +++ b/pandora_agents/win32/modules/pandora_module_proc.cc @@ -45,7 +45,10 @@ Pandora_Module_Proc::Pandora_Module_Proc (string name, string process_name) transform (process_name.begin (), process_name.end (), this->process_name.begin (), (int (*) (int)) tolower); - this->setKind (module_proc_str); + this->setKind (module_proc_str); + + this->watchdog = false; + this->start_command = ""; } string @@ -53,6 +56,26 @@ Pandora_Module_Proc::getProcessName () const { return this->process_name; } +bool +Pandora_Module_Proc::isWatchdog () const { + return this->watchdog; +} + +string +Pandora_Module_Proc::getStartCommand () const { + return this->start_command; +} + +void +Pandora_Module_Proc::setWatchdog (bool watchdog) { + this->watchdog = watchdog; +} + +void +Pandora_Module_Proc::setStartCommand (string command) { + this->start_command = command; +} + void async_run (Pandora_Module_Proc *module) { HANDLE *processes = NULL; @@ -72,6 +95,9 @@ async_run (Pandora_Module_Proc *module) { while (1) { processes = getProcessHandles (module->getProcessName ()); if (processes == NULL) { + if (module->isWatchdog ()) { + Pandora_Wmi::runProgram (module->getStartCommand ()); + } Sleep (2000); continue; } @@ -106,6 +132,10 @@ async_run (Pandora_Module_Proc *module) { Pandora_Windows_Service::getInstance ()->sendXml (modules); } + if (res == 0 && module->isWatchdog ()) { + Pandora_Wmi::runProgram (module->getStartCommand ()); + } + /* Free handles */ for (i = 0; i < nprocess; i++) CloseHandle (processes[i]); diff --git a/pandora_agents/win32/modules/pandora_module_proc.h b/pandora_agents/win32/modules/pandora_module_proc.h index 96d1baab81..392b17435c 100644 --- a/pandora_agents/win32/modules/pandora_module_proc.h +++ b/pandora_agents/win32/modules/pandora_module_proc.h @@ -30,13 +30,20 @@ namespace Pandora_Modules { class Pandora_Module_Proc : public Pandora_Module { private: string process_name; - HANDLE thread; + HANDLE thread; + bool watchdog; + string start_command; public: - Pandora_Module_Proc (string name, string process_name); + Pandora_Module_Proc (string name, string process_name); - string getProcessName () const; + string getProcessName () const; + string getStartCommand () const; + bool isWatchdog () const; + + void setWatchdog (bool watchdog); + void setStartCommand (string command); - void run (); + void run (); }; } diff --git a/pandora_agents/win32/modules/pandora_module_service.cc b/pandora_agents/win32/modules/pandora_module_service.cc index aa06de51d3..eb75646aa0 100644 --- a/pandora_agents/win32/modules/pandora_module_service.cc +++ b/pandora_agents/win32/modules/pandora_module_service.cc @@ -46,7 +46,8 @@ Pandora_Module_Service::Pandora_Module_Service (string name, string service_name this->service_name.begin (), (int (*) (int)) tolower); this->setKind (module_service_str); - this->thread = 0; + this->thread = 0; + this->watchdog = false; } string @@ -54,6 +55,17 @@ Pandora_Module_Service::getServiceName () const { return this->service_name; } + +bool +Pandora_Module_Service::isWatchdog () const { + return this->watchdog; +} + +void +Pandora_Module_Service::setWatchdog (bool watchdog) { + this->watchdog = watchdog; +} + #define BUFFER_SIZE (16384) void @@ -107,8 +119,8 @@ async_run (Pandora_Module_Service *module) { continue; event_id = record->EventID & 0x0000ffff; - /* Those numbers are the code for service start/stopping */ - if (event_id == 7035 || event_id == 7036) { + /* This number is the code for service start/stopping */ + if (event_id == 7036) { service_event = true; break; } @@ -123,6 +135,10 @@ async_run (Pandora_Module_Service *module) { prev_res = str_res; Pandora_Windows_Service::getInstance ()->sendXml (modules); } + + if (res == 0 && module->isWatchdog ()) { + Pandora_Wmi::startService (module->getServiceName ()); + } } CloseHandle (event); CloseEventLog (event_log); diff --git a/pandora_agents/win32/modules/pandora_module_service.h b/pandora_agents/win32/modules/pandora_module_service.h index 3cb1101a91..3ebf2fdf86 100644 --- a/pandora_agents/win32/modules/pandora_module_service.h +++ b/pandora_agents/win32/modules/pandora_module_service.h @@ -32,12 +32,16 @@ namespace Pandora_Modules { class Pandora_Module_Service : public Pandora_Module { private: string service_name; - HANDLE thread; + HANDLE thread; + bool watchdog; public: Pandora_Module_Service (string name, string service_name); - void run (); - string getServiceName () const; + void run (); + string getServiceName () const; + bool isWatchdog () const; + + void setWatchdog (bool watchdog); }; } diff --git a/pandora_agents/win32/pandora.cc b/pandora_agents/win32/pandora.cc index 5015451df8..b1b0cfaa36 100644 --- a/pandora_agents/win32/pandora.cc +++ b/pandora_agents/win32/pandora.cc @@ -272,3 +272,22 @@ string Pandora::getPandoraAgentVersion () { return pandora_version; } + + +bool +Pandora::is_enabled (string value) { + static string enabled_values[] = {"enabled", "1", "on", "yes", "si", "sí", "ok", "true", ""}; + int i = 0; + + if (value == "") { + return false; + } + + while (enabled_values[i] != "") { + if (enabled_values[i] == value) { + return true; + } + i++; + } + return false; +} diff --git a/pandora_agents/win32/pandora.h b/pandora_agents/win32/pandora.h index 57aec9377d..05ec963629 100644 --- a/pandora_agents/win32/pandora.h +++ b/pandora_agents/win32/pandora.h @@ -66,7 +66,8 @@ namespace Pandora { void pandoraDebug (char *format, ...); void pandoraLog (char *format, ...); void pandoraFree (void * e); - + + bool is_enabled (string value); /** * Super-class exception. * diff --git a/pandora_agents/win32/pandora_windows_service.cc b/pandora_agents/win32/pandora_windows_service.cc index 2284f232b4..8886043044 100644 --- a/pandora_agents/win32/pandora_windows_service.cc +++ b/pandora_agents/win32/pandora_windows_service.cc @@ -37,8 +37,6 @@ using namespace std; using namespace Pandora; using namespace Pandora_Modules; using namespace Pandora_Strutils; - -string enabled_values[] = {"enabled", "1", "on", "yes", "si", "sí", "ok", ""}; Pandora_Windows_Service::Pandora_Windows_Service () : Windows_Service (NULL, NULL, NULL) { @@ -101,23 +99,6 @@ Pandora_Windows_Service::getInstance () { void Pandora_Windows_Service::start () { this->started = true; -} - -bool -is_enabled (string value) { - int i = 0; - - if (value == "") { - return false; - } - - while (enabled_values[i] != "") { - if (enabled_values[i] == value) { - return true; - } - i++; - } - return false; } void diff --git a/pandora_agents/win32/windows/pandora_wmi.cc b/pandora_agents/win32/windows/pandora_wmi.cc index def83d087f..75e83f046f 100644 --- a/pandora_agents/win32/windows/pandora_wmi.cc +++ b/pandora_agents/win32/windows/pandora_wmi.cc @@ -25,17 +25,18 @@ #include #include #include -#include +#include +#include using namespace std; using namespace Pandora_Wmi; static LPWSTR getWmiStr (LPCWSTR computer) { - static WCHAR wmi_str [256]; - - wcscpy (wmi_str, L"winmgmts:{impersonationLevel=impersonate}!\\\\"); + static WCHAR wmi_str[256]; + wcscpy (wmi_str, L"winmgmts:\\\\"); + if (computer) { wcsncat (wmi_str, computer, 128); } else { @@ -43,7 +44,7 @@ getWmiStr (LPCWSTR computer) { } wcscat (wmi_str, L"\\root\\cimv2"); - + return wmi_str; } @@ -388,7 +389,9 @@ Pandora_Wmi::getSystemName () { * @return The list of events. */ void -Pandora_Wmi::getEventList (string source, string type, string code, string pattern, int interval, list &event_list) { +Pandora_Wmi::getEventList (string source, string type, string code, + string pattern, int interval, + list &event_list) { CDhInitialize init; CDispPtr wmi_svc, quickfixes; char *value = NULL; @@ -453,8 +456,8 @@ Pandora_Wmi::getEventList (string source, string type, string code, string patte */ string Pandora_Wmi::getTimestampLimit (int interval) { - char limit_str[26], diff_sign; - time_t limit_time, limit_time_utc, limit_diff; + char limit_str[26], diff_sign; + time_t limit_time, limit_time_utc, limit_diff; struct tm *limit_tm = NULL, *limit_tm_utc = NULL; // Get current time @@ -511,4 +514,121 @@ Pandora_Wmi::convertWMIDate (string wmi_date, SYSTEMTIME *system_time) system_time->wHour = atoi (wmi_date.substr (8, 2).c_str()); system_time->wMinute = atoi (wmi_date.substr (10, 2).c_str()); system_time->wSecond = atoi (wmi_date.substr (12, 2).c_str()); -} +} + +/** + * Runs a program in a new process. + * + * @param command Command to run, with parameters + */ +bool +Pandora_Wmi::runProgram (string command) { + PROCESS_INFORMATION process_info; + STARTUPINFO startup_info; + bool success; + char *cmd; + + if (command == "") + return false; + + ZeroMemory (&startup_info, sizeof (startup_info)); + startup_info.cb = sizeof (startup_info); + ZeroMemory (&process_info, sizeof (process_info)); + + pandoraDebug ("Start process \"%s\".", command.c_str ()); + cmd = strdup (command.c_str ()); + success = CreateProcess (NULL, cmd, NULL, NULL, FALSE, 0, + NULL, NULL, &startup_info, &process_info); + pandoraFree (cmd); + + if (success) { + pandoraDebug ("The process \"%s\" was started.", command.c_str ()); + return true; + } + pandoraLog ("Could not start process \"%s\". Error %d", command.c_str (), + GetLastError()); + return false; +} + +/** + * Start a Windows service. + * + * @param service_name Service internal name to start. + * + * @retval true If the service started. + * @retval false If the service could not start. A log message is created. + */ +bool +Pandora_Wmi::startService (string service_name) { + SC_HANDLE manager, service; + bool success; + + manager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (manager == NULL) { + pandoraLog ("Could not access to service \"%s\" to start.", + service_name.c_str ()); + return false; + } + + service = OpenService (manager, service_name.c_str (), GENERIC_EXECUTE); + if (service == NULL) { + pandoraLog ("Could not access to service \"%s\" to start.", + service_name.c_str ()); + CloseServiceHandle (manager); + return false; + } + + success = StartService (service, 0, NULL); + + CloseServiceHandle (service); + CloseServiceHandle (manager); + + if (! success) { + pandoraLog ("Could not start service \"%s\". (Error %d)", + service_name.c_str (), GetLastError ()); + } + + return success; +} + +/** + * Stop a Windows service. + * + * @param service_name Service internal name to stop. + * + * @retval true If the service started. + * @retval false If the service could not stop. A log message is created. + */ +bool +Pandora_Wmi::stopService (string service_name) { + SC_HANDLE manager, service; + bool success; + + manager = OpenSCManager (NULL, NULL, SC_MANAGER_ALL_ACCESS); + if (manager == NULL) { + pandoraLog ("Could not access to service \"%s\" to stop.", + service_name.c_str ()); + return false; + } + + service = OpenService (manager, service_name.c_str (), GENERIC_EXECUTE); + if (service == NULL) { + pandoraLog ("Could not access to service \"%s\" to stop.", + service_name.c_str ()); + CloseServiceHandle (manager); + return false; + } + + success = ControlService (service, SERVICE_CONTROL_STOP, NULL); + + CloseServiceHandle (service); + CloseServiceHandle (manager); + + if (! success) { + pandoraLog ("Could not stop service \"%s\". (Error %d)", + service_name.c_str (), GetLastError ()); + } + + return success; +} + diff --git a/pandora_agents/win32/windows/pandora_wmi.h b/pandora_agents/win32/windows/pandora_wmi.h index 612fc64088..28b3f7c9f0 100644 --- a/pandora_agents/win32/windows/pandora_wmi.h +++ b/pandora_agents/win32/windows/pandora_wmi.h @@ -46,10 +46,21 @@ namespace Pandora_Wmi { string getOSName (); string getOSVersion (); string getOSBuild (); - string getSystemName (); - void getEventList (string source, string type, string code, string pattern, int interval, list &event_list); - string getTimestampLimit (int interval); - void convertWMIDate (string wmi_date, SYSTEMTIME *system_time); + string getSystemName (); + + void getEventList (string source, + string type, + string code, + string pattern, + int interval, + list &event_list); + string getTimestampLimit (int interval); + void convertWMIDate (string wmi_date, + SYSTEMTIME *system_time); + + bool runProgram (string command); + bool startService (string service_name); + bool stopService (string service_name); }; #endif diff --git a/pandora_agents/win32/windows_service.cc b/pandora_agents/win32/windows_service.cc index c53e71bb0e..faa2c785b1 100644 --- a/pandora_agents/win32/windows_service.cc +++ b/pandora_agents/win32/windows_service.cc @@ -202,19 +202,20 @@ Windows_Service::install (LPCTSTR application_binary_path) { } /* Crerate the service */ - sc_service = CreateService (sc_manager, /* SCManager database */ - service_name, /* name of service */ - service_display_name, /* service name to display */ - SERVICE_ALL_ACCESS, /* desired access */ - SERVICE_WIN32_OWN_PROCESS, /* service type */ - SERVICE_AUTO_START, /* start type */ - SERVICE_ERROR_NORMAL, /* error control type */ - application_binary_path, /* service's binary */ - NULL, /* no load ordering group */ - NULL, /* no tag identifier */ - NULL, /* no dependencies */ - NULL, /* LocalSystem account */ - NULL /* no password */ ); + sc_service = CreateService (sc_manager, /* SCManager database */ + service_name, /* name of service */ + service_display_name, /* service name to display */ + SERVICE_ALL_ACCESS, /* desired access */ + SERVICE_WIN32_OWN_PROCESS | + SERVICE_INTERACTIVE_PROCESS, /* service type, interactive */ + SERVICE_AUTO_START, /* start type */ + SERVICE_ERROR_NORMAL, /* error control type */ + application_binary_path, /* service's binary */ + NULL, /* no load ordering group */ + NULL, /* no tag identifier */ + NULL, /* no dependencies */ + NULL, /* LocalSystem account */ + NULL /* no password */ ); if (sc_service == NULL) { DWORD err = GetLastError();