2008-11-28 Esteban Sanchez <estebans@artica.es>

* modules/pandora_module.[cc,h]: Added an async property. Added
	getLatestOutput() to get the latest output of a module.

	* modules/pandora_module_factory.cc: Parse async token in modules.

	* modules/pandora_module_list.[cc,h]: It can create empty lists now
	and add modules using new addModule() function.

	* modules/pandora_module_service.[cc,h]: Added an async thread to
	watch services events and track services status changes quickly and
	asynchronously.

	* windows/pandora_wmi.cc: Style correction.

	* pandora_windows_service.[cc,h]: Pandora Windows service object is
	now single instance, so the instance to the running service can be
	accessed anywhere (useful in async threads). The XML generation and
	sending process has been moved to a new function called sendXml()
	which is thread-safe.

	* windows_service.h: Some properties are now protected instead of
	public to make it easier the singleton pattern in child classes.

	* main.cc: Adopted to singleton pattern in Pandora windows service.



git-svn-id: https://svn.code.sf.net/p/pandora/code/trunk@1268 c3f86ba8-e40f-0410-aaad-9ba5e7f4b01f
This commit is contained in:
Esteban Sanchez 2008-11-28 10:51:03 +00:00
parent 453c3d534d
commit 5a63e70b7b
14 changed files with 804 additions and 568 deletions

View File

@ -1,3 +1,30 @@
2008-11-28 Esteban Sanchez <estebans@artica.es>
* modules/pandora_module.[cc,h]: Added an async property. Added
getLatestOutput() to get the latest output of a module.
* modules/pandora_module_factory.cc: Parse async token in modules.
* modules/pandora_module_list.[cc,h]: It can create empty lists now
and add modules using new addModule() function.
* modules/pandora_module_service.[cc,h]: Added an async thread to
watch services events and track services status changes quickly and
asynchronously.
* windows/pandora_wmi.cc: Style correction.
* pandora_windows_service.[cc,h]: Pandora Windows service object is
now single instance, so the instance to the running service can be
accessed anywhere (useful in async threads). The XML generation and
sending process has been moved to a new function called sendXml()
which is thread-safe.
* windows_service.h: Some properties are now protected instead of
public to make it easier the singleton pattern in child classes.
* main.cc: Adopted to singleton pattern in Pandora windows service.
2008-11-26 Esteban Sanchez <estebans@artica.es> 2008-11-26 Esteban Sanchez <estebans@artica.es>
* pandora_strutils.cc, pandora_strutils.h, ftp/pandora_ftp_client.cc, * pandora_strutils.cc, pandora_strutils.h, ftp/pandora_ftp_client.cc,

View File

@ -1,129 +1,131 @@
/* Pandora Windows agent main file. /* Pandora Windows agent main file.
Copyright (C) 2006 Artica ST. Copyright (C) 2006 Artica ST.
Written by Esteban Sanchez. Written by Esteban Sanchez.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option) the Free Software Foundation; either version 2, or (at your option)
any later version. any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License along You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include "pandora.h" #include "pandora.h"
#include "pandora_windows_service.h" #include "pandora_windows_service.h"
#include "ssh/pandora_ssh_test.h" #include "ssh/pandora_ssh_test.h"
#include "ftp/pandora_ftp_test.h" #include "ftp/pandora_ftp_test.h"
#define PATH_SIZE _MAX_PATH+1 #define PATH_SIZE _MAX_PATH+1
#define SERVICE_INSTALL_CMDLINE_PARAM "--install" #define SERVICE_INSTALL_CMDLINE_PARAM "--install"
#define SERVICE_UNINSTALL_CMDLINE_PARAM "--uninstall" #define SERVICE_UNINSTALL_CMDLINE_PARAM "--uninstall"
#define SSH_TEST_CMDLINE_PARAM "--test-ssh" #define SSH_TEST_CMDLINE_PARAM "--test-ssh"
#define FTP_TEST_CMDLINE_PARAM "--test-ftp" #define FTP_TEST_CMDLINE_PARAM "--test-ftp"
#define HELP_CMDLINE_PARAM "--help" #define HELP_CMDLINE_PARAM "--help"
int int
main (int argc, char *argv[]) { main (int argc, char *argv[]) {
Pandora_Windows_Service *service; Pandora_Windows_Service *service;
char buffer[PATH_SIZE]; char buffer[PATH_SIZE];
string aux; string aux;
unsigned int pos; unsigned int pos;
service = new Pandora_Windows_Service (Pandora::name, Pandora::display_name, service = Pandora_Windows_Service::getInstance ();
Pandora::description); service->setValues (Pandora::name, Pandora::display_name,
Pandora::description);
GetModuleFileName (NULL, buffer, MAX_PATH); service->start ();
aux = buffer;
Pandora::setPandoraInstallPath (aux); GetModuleFileName (NULL, buffer, MAX_PATH);
pos = aux.rfind ("\\"); aux = buffer;
aux.erase (pos + 1); Pandora::setPandoraInstallPath (aux);
Pandora::setPandoraInstallDir (aux); pos = aux.rfind ("\\");
aux.erase (pos + 1);
/* Check the parameters */ Pandora::setPandoraInstallDir (aux);
for (int i = 1; i < argc; i++) {
if (_stricmp(argv[i], SERVICE_INSTALL_CMDLINE_PARAM) == 0) { /* Check the parameters */
/* Install parameter */ for (int i = 1; i < argc; i++) {
service->install (Pandora::getPandoraInstallPath ().c_str ()); if (_stricmp(argv[i], SERVICE_INSTALL_CMDLINE_PARAM) == 0) {
/* Install parameter */
delete service; service->install (Pandora::getPandoraInstallPath ().c_str ());
return 0; delete service;
} else if (_stricmp(argv[i], SERVICE_UNINSTALL_CMDLINE_PARAM) == 0) {
/* Uninstall parameter */ return 0;
service->uninstall (); } else if (_stricmp(argv[i], SERVICE_UNINSTALL_CMDLINE_PARAM) == 0) {
/* Uninstall parameter */
delete service; service->uninstall ();
return 0; delete service;
} else if (_stricmp(argv[i], SSH_TEST_CMDLINE_PARAM) == 0) {
/* SSH test parameter */ return 0;
SSH::Pandora_SSH_Test ssh_test; } else if (_stricmp(argv[i], SSH_TEST_CMDLINE_PARAM) == 0) {
/* SSH test parameter */
delete service; SSH::Pandora_SSH_Test ssh_test;
try { delete service;
ssh_test.test ();
} catch (Pandora_Exception e) { try {
return 1; ssh_test.test ();
} } catch (Pandora_Exception e) {
return 1;
return 0; }
} else if (_stricmp(argv[i], FTP_TEST_CMDLINE_PARAM) == 0) {
/* SSH test parameter */ return 0;
FTP::Pandora_FTP_Test ftp_test; } else if (_stricmp(argv[i], FTP_TEST_CMDLINE_PARAM) == 0) {
/* SSH test parameter */
delete service; FTP::Pandora_FTP_Test ftp_test;
try { delete service;
ftp_test.test ();
} catch (Pandora_Exception e) { try {
return 1; ftp_test.test ();
} } catch (Pandora_Exception e) {
return 1;
return 0; }
} else if (_stricmp(argv[i], HELP_CMDLINE_PARAM) == 0) { return 0;
/* Help parameter */
cout << "Pandora agent for Windows. "; } else if (_stricmp(argv[i], HELP_CMDLINE_PARAM) == 0) {
cout << "Version " << getPandoraAgentVersion () << endl; /* Help parameter */
cout << "Usage: " << argv[0] << " [OPTION]" << endl << endl; cout << "Pandora agent for Windows. ";
cout << "Available options are:" << endl; cout << "Version " << getPandoraAgentVersion () << endl;
cout << "\t" << SERVICE_INSTALL_CMDLINE_PARAM; cout << "Usage: " << argv[0] << " [OPTION]" << endl << endl;
cout << ": Install the Pandora Agent service." << endl; cout << "Available options are:" << endl;
cout << "\t" << SERVICE_UNINSTALL_CMDLINE_PARAM; cout << "\t" << SERVICE_INSTALL_CMDLINE_PARAM;
cout << ": Uninstall the Pandora Agent service." << endl; cout << ": Install the Pandora Agent service." << endl;
cout << "\t" << SSH_TEST_CMDLINE_PARAM; cout << "\t" << SERVICE_UNINSTALL_CMDLINE_PARAM;
cout << ": Test the SSH Pandora Agent configuration." << endl; cout << ": Uninstall the Pandora Agent service." << endl;
cout << "\t" << FTP_TEST_CMDLINE_PARAM; cout << "\t" << SSH_TEST_CMDLINE_PARAM;
cout << ": Test the FTP Pandora Agent configuration." << endl; cout << ": Test the SSH Pandora Agent configuration." << endl;
cout << "\t" << FTP_TEST_CMDLINE_PARAM;
return 0; cout << ": Test the FTP Pandora Agent configuration." << endl;
} else {
/* No parameter recognized */ return 0;
cout << "Pandora agent for Windows. "; } else {
cout << "Version " << getPandoraAgentVersion () << endl; /* No parameter recognized */
cout << "Usage: " << argv[0] << " [" << SERVICE_INSTALL_CMDLINE_PARAM; cout << "Pandora agent for Windows. ";
cout << "] [" << SERVICE_UNINSTALL_CMDLINE_PARAM; cout << "Version " << getPandoraAgentVersion () << endl;
cout << "] [" << SSH_TEST_CMDLINE_PARAM; cout << "Usage: " << argv[0] << " [" << SERVICE_INSTALL_CMDLINE_PARAM;
cout << "] [" << FTP_TEST_CMDLINE_PARAM << "]"; cout << "] [" << SERVICE_UNINSTALL_CMDLINE_PARAM;
cout << endl << endl; cout << "] [" << SSH_TEST_CMDLINE_PARAM;
cout << "Run " << argv[0] << " with " << HELP_CMDLINE_PARAM; cout << "] [" << FTP_TEST_CMDLINE_PARAM << "]";
cout << " parameter for more info." << endl; cout << endl << endl;
cout << "Run " << argv[0] << " with " << HELP_CMDLINE_PARAM;
return 1; cout << " parameter for more info." << endl;
}
} return 1;
service->run (); }
}
delete service; service->run ();
return 0; delete service;
}
return 0;
}

View File

@ -39,7 +39,8 @@ Pandora_Module::Pandora_Module (string name) {
this->module_interval = 1; this->module_interval = 1;
this->max = 0; this->max = 0;
this->min = 0; this->min = 0;
this->has_limits = false; this->has_limits = false;
this->async = false;
this->data_list = NULL; this->data_list = NULL;
} }
@ -175,6 +176,21 @@ Module_Kind
Pandora_Module::getModuleKind () const { Pandora_Module::getModuleKind () const {
return this->module_kind; return this->module_kind;
} }
/**
* Get the output of the module.
*
* @return The module output in a string value.
*/
string
Pandora_Module::getLatestOutput () const {
list<Pandora_Data *>::iterator iter;
if (this->data_list == NULL)
return "";
iter = this->data_list->begin ();
return (*iter)->getValue ();
}
/** /**
* Get the type of the module in a integer_value. * Get the type of the module in a integer_value.
@ -222,7 +238,7 @@ Pandora_Module::getDataOutput (Pandora_Data *data) {
} }
} }
return trim(data->getValue ()); return trim (data->getValue ());
} }
/** /**
@ -351,15 +367,16 @@ Pandora_Module::getXml () {
data_element = new TiXmlElement ("data"); data_element = new TiXmlElement ("data");
element = new TiXmlElement ("value"); element = new TiXmlElement ("value");
try { try {
data_clean = strreplace (this->getDataOutput (data), "%", "%%" ); data_clean = strreplace (this->getDataOutput (data),
} catch (Output_Error e) { "%", "%%" );
delete element; } catch (Output_Error e) {
continue; delete element;
} continue;
}
text = new TiXmlText (data_clean);
element->InsertEndChild (*text); text = new TiXmlText (data_clean);
data_element->InsertEndChild (*element); element->InsertEndChild (*text);
data_element->InsertEndChild (*element);
delete text; delete text;
delete element; delete element;
@ -379,11 +396,11 @@ Pandora_Module::getXml () {
data = data_list->front (); data = data_list->front ();
element = new TiXmlElement ("data"); element = new TiXmlElement ("data");
try { try {
data_clean = strreplace (this->getDataOutput (data), "%", "%%" ); data_clean = strreplace (this->getDataOutput (data), "%", "%%" );
text = new TiXmlText (data_clean); text = new TiXmlText (data_clean);
element->InsertEndChild (*text); element->InsertEndChild (*text);
root->InsertEndChild (*element); root->InsertEndChild (*element);
delete text; delete text;
} catch (Output_Error e) { } catch (Output_Error e) {
} }
delete element; delete element;
@ -412,7 +429,7 @@ void
Pandora_Module::setMax (int value) { Pandora_Module::setMax (int value) {
this->has_limits = true; this->has_limits = true;
this->max = value; this->max = value;
} }
/** /**
* Set the min value the module can have. * Set the min value the module can have.
@ -426,6 +443,19 @@ Pandora_Module::setMin (int value) {
this->has_limits = true; this->has_limits = true;
this->min = value; this->min = value;
} }
/**
* Set the async flag to the module.
*
* If a module is set to be async, it would try to works only when the
* events happen. Note that not all the modules can work in async mode.
*
* @param async Flag to set.
*/
void
Pandora_Module::setAsync (bool async) {
this->async = async;
}
/** /**
* Set the module type from a string type. * Set the module type from a string type.

View File

@ -80,7 +80,7 @@ namespace Pandora_Modules {
const string module_freememory_str = "module_freememory"; const string module_freememory_str = "module_freememory";
const string module_cpuusage_str = "module_cpuusage"; const string module_cpuusage_str = "module_cpuusage";
const string module_odbc_str = "module_odbc"; const string module_odbc_str = "module_odbc";
const string module_logevent_str = "module_logevent"; const string module_logevent_str = "module_logevent";
/** /**
* Pandora module super-class exception. * Pandora module super-class exception.
@ -134,7 +134,12 @@ namespace Pandora_Modules {
/** /**
* The description of the module. * The description of the module.
*/ */
string module_description; string module_description;
/**
* Flag to set a module as asynchronous
*/
bool async;
public: public:
Pandora_Module (string name); Pandora_Module (string name);
virtual ~Pandora_Module (); virtual ~Pandora_Module ();
@ -145,29 +150,32 @@ namespace Pandora_Modules {
static Module_Kind static Module_Kind
parseModuleKindFromString (string kind); parseModuleKindFromString (string kind);
void setInterval (int interval); void setInterval (int interval);
int getInterval (); int getInterval ();
TiXmlElement *getXml (); TiXmlElement *getXml ();
virtual void run (); virtual void run ();
virtual void setOutput (string output); virtual void setOutput (string output);
virtual void setOutput (string output, SYSTEMTIME *system_time); virtual void setOutput (string output,
SYSTEMTIME *system_time);
string getName () const; string getName () const;
string getDescription () const; string getDescription () const;
string getTypeString () const; string getTypeString () const;
Module_Type getTypeInt () const; string getLatestOutput () const;
Module_Type getModuleType () const; Module_Type getTypeInt () const;
Module_Kind getModuleKind () const; Module_Type getModuleType () const;
Module_Kind getModuleKind () const;
void setType (string type); void setType (string type);
void setKind (string kind); void setKind (string kind);
void setDescription (string description); void setDescription (string description);
void setMax (int value); void setMax (int value);
void setMin (int value); void setMin (int value);
void setAsync (bool async);
}; };
} }

View File

@ -52,7 +52,8 @@ using namespace Pandora_Strutils;
#define TOKEN_LOGEVENT ("module_logevent") #define TOKEN_LOGEVENT ("module_logevent")
#define TOKEN_SOURCE ("module_source ") #define TOKEN_SOURCE ("module_source ")
#define TOKEN_EVENTTYPE ("module_eventtype ") #define TOKEN_EVENTTYPE ("module_eventtype ")
#define TOKEN_PATTERN ("module_pattern ") #define TOKEN_PATTERN ("module_pattern ")
#define TOKEN_ASYNC ("module_async")
string string
parseLine (string line, string token) { parseLine (string line, string token) {
@ -87,7 +88,8 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) {
string module_interval, module_proc, module_service; string module_interval, module_proc, module_service;
string module_freedisk, module_cpuusage, module_odbc; string module_freedisk, module_cpuusage, module_odbc;
string module_odbc_query, module_dsn, module_freememory; string module_odbc_query, module_dsn, module_freememory;
string module_logevent, module_source, module_eventtype, module_pattern; string module_logevent, module_source, module_eventtype;
string module_pattern, module_async;
Pandora_Module *module; Pandora_Module *module;
bool numeric; bool numeric;
Module_Type type; Module_Type type;
@ -104,10 +106,10 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) {
module_odbc = ""; module_odbc = "";
module_odbc_query = ""; module_odbc_query = "";
module_odbc = ""; module_odbc = "";
module_logevent = ""; module_logevent = "";
module_source = ""; module_source = "";
module_eventtype = ""; module_eventtype = "";
module_pattern = ""; module_pattern = "";
stringtok (tokens, definition, "\n"); stringtok (tokens, definition, "\n");
@ -160,18 +162,21 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) {
if (module_odbc_query == "") { if (module_odbc_query == "") {
module_odbc_query = parseLine (line, TOKEN_ODBC_QUERY); module_odbc_query = parseLine (line, TOKEN_ODBC_QUERY);
} }
if (module_logevent == "") { if (module_logevent == "") {
module_logevent = parseLine (line, TOKEN_LOGEVENT); module_logevent = parseLine (line, TOKEN_LOGEVENT);
} }
if (module_source == "") { if (module_source == "") {
module_source = parseLine (line, TOKEN_SOURCE); module_source = parseLine (line, TOKEN_SOURCE);
} }
if (module_eventtype == "") { if (module_eventtype == "") {
module_eventtype = parseLine (line, TOKEN_EVENTTYPE); module_eventtype = parseLine (line, TOKEN_EVENTTYPE);
} }
if (module_pattern == "") { if (module_pattern == "") {
module_pattern = parseLine (line, TOKEN_PATTERN); module_pattern = parseLine (line, TOKEN_PATTERN);
} }
if (module_async == "") {
module_async = parseLine (line, TOKEN_ASYNC);
}
iter++; iter++;
} }
@ -220,8 +225,12 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) {
if (module_description != "") { if (module_description != "") {
module->setDescription (module_description); module->setDescription (module_description);
} }
if (module_async != "") {
module->setAsync (true);
}
type = Pandora_Module::parseModuleTypeFromString (module_type); type = Pandora_Module::parseModuleTypeFromString (module_type);
switch (type) { switch (type) {
case TYPE_GENERIC_DATA: case TYPE_GENERIC_DATA:
@ -258,7 +267,7 @@ Pandora_Module_Factory::getModuleFromDefinition (string definition) {
} }
} }
if (module_min != "") { if (module_min != "") {
try { try {
int value = strtoint (module_min); int value = strtoint (module_min);
module->setMin (value); module->setMin (value);

View File

@ -80,8 +80,26 @@ Pandora_Modules::Pandora_Module_List::Pandora_Module_List (string filename) {
file.close (); file.close ();
current = new std::list<Pandora_Module *>::iterator (); current = new std::list<Pandora_Module *>::iterator ();
*current = modules->begin (); (*current) = modules->begin ();
} }
/**
* Creates an empty module list object.
*/
Pandora_Modules::Pandora_Module_List::Pandora_Module_List () {
this->modules = new list<Pandora_Module *> ();
current = new std::list<Pandora_Module *>::iterator ();
(*current) = modules->begin ();
}
/**
* Adds a module object to a list object.
*/
void
Pandora_Modules::Pandora_Module_List::addModule (Pandora_Module *module) {
modules->push_back (module);
}
/** /**
* Destroy the list. * Destroy the list.

View File

@ -42,11 +42,15 @@ namespace Pandora_Modules {
list<Pandora_Module *>::iterator *current; list<Pandora_Module *>::iterator *current;
void parseModuleDefinition (string definition); void parseModuleDefinition (string definition);
public: public:
Pandora_Module_List (string filename); Pandora_Module_List (string filename);
Pandora_Module_List ();
~Pandora_Module_List (); ~Pandora_Module_List ();
Pandora_Module * getCurrentValue (); Pandora_Module * getCurrentValue ();
/* Add a module to the list */
void addModule (Pandora_Module *module);
/* Move to the first element of the list */ /* Move to the first element of the list */
void goFirst (); void goFirst ();

View File

@ -19,9 +19,11 @@
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include "pandora_module_service.h" #include "pandora_module_service.h"
#include "pandora_module_list.h"
#include "../windows/pandora_wmi.h" #include "../windows/pandora_wmi.h"
#include "../pandora_strutils.h" #include "../pandora_strutils.h"
#include "../pandora_windows_service.h"
#include <algorithm> #include <algorithm>
#include <cctype> #include <cctype>
@ -43,8 +45,84 @@ Pandora_Module_Service::Pandora_Module_Service (string name, string service_name
transform (service_name.begin (), service_name.end (), transform (service_name.begin (), service_name.end (),
this->service_name.begin (), (int (*) (int)) tolower); this->service_name.begin (), (int (*) (int)) tolower);
this->setKind (module_service_str); this->setKind (module_service_str);
this->thread = 0;
} }
string
Pandora_Module_Service::getServiceName () const {
return this->service_name;
}
#define BUFFER_SIZE (16384)
void
async_run (Pandora_Module_Service *module) {
HANDLE event_log;
HANDLE event;
DWORD result;
int res;
string str_res;
BYTE buffer[BUFFER_SIZE];
EVENTLOGRECORD *record;
DWORD read;
DWORD needed;
int event_id;
bool service_event;
string prev_res;
Pandora_Module_List *modules;
prev_res = module->getLatestOutput ();
modules = new Pandora_Module_List ();
modules->addModule (module);
while (1) {
event_log = OpenEventLog (NULL, "Service Control Manager");
if (event_log == NULL) {
pandoraLog ("Could not open event log for %s.",
module->getServiceName ().c_str ());
return;
}
event = CreateEvent (NULL, FALSE, FALSE, NULL);
NotifyChangeEventLog (event_log, event);
result = WaitForSingleObject (event, 10000);
if (result == 0) {
service_event = false;
record = (EVENTLOGRECORD *) buffer;
while (ReadEventLog (event_log,
EVENTLOG_FORWARDS_READ | EVENTLOG_SEQUENTIAL_READ,
0, record, BUFFER_SIZE, &read, &needed)) {
if (record->EventType != EVENTLOG_INFORMATION_TYPE)
continue;
event_id = record->EventID & 0x0000ffff;
/* Those numbers are the code for service start/stopping */
if (event_id == 7035 || event_id == 7036) {
service_event = true;
break;
}
}
if (service_event) {
res = Pandora_Wmi::isServiceRunning (module->getServiceName ());
str_res = inttostr (res);
if (str_res != prev_res) {
module->setOutput (str_res);
prev_res = str_res;
pandoraLog ("Service \"%s\" changed status to: %d",
module->getServiceName ().c_str (), res);
Pandora_Windows_Service::getInstance ()->sendXml (modules);
}
}
}
CloseHandle (event);
CloseEventLog (event_log);
}
delete modules;
}
void void
Pandora_Module_Service::run () { Pandora_Module_Service::run () {
@ -57,5 +135,13 @@ Pandora_Module_Service::run () {
} }
res = Pandora_Wmi::isServiceRunning (this->service_name); res = Pandora_Wmi::isServiceRunning (this->service_name);
this->setOutput (inttostr (res)); this->setOutput (inttostr (res));
/* Launch thread if it's asynchronous */
if (this->async) {
this->thread = CreateThread (NULL, 0,
(LPTHREAD_START_ROUTINE) async_run,
this, 0, NULL);
this->async = false;
}
} }

View File

@ -31,11 +31,13 @@ namespace Pandora_Modules {
*/ */
class Pandora_Module_Service : public Pandora_Module { class Pandora_Module_Service : public Pandora_Module {
private: private:
string service_name; string service_name;
HANDLE thread;
public: public:
Pandora_Module_Service (string name, string service_name); Pandora_Module_Service (string name, string service_name);
void run (); void run ();
string getServiceName () const;
}; };
} }

View File

@ -1,274 +1,274 @@
/* Common functions to any Pandora program. /* Common functions to any Pandora program.
Copyright (C) 2006 Artica ST. Copyright (C) 2006 Artica ST.
Written by Esteban Sanchez. Written by Esteban Sanchez.
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option) the Free Software Foundation; either version 2, or (at your option)
any later version. any later version.
This program is distributed in the hope that it will be useful, This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details. GNU General Public License for more details.
You should have received a copy of the GNU General Public License along You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, with this program; if not, write to the Free Software Foundation,
Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/ */
#include <stdio.h> #include <stdio.h>
#include <iostream> #include <iostream>
#include <cctype> #include <cctype>
#include <string> #include <string>
#include <algorithm> #include <algorithm>
#include "pandora.h" #include "pandora.h"
#include "pandora_strutils.h" #include "pandora_strutils.h"
using namespace std; using namespace std;
using namespace Pandora; using namespace Pandora;
using namespace Pandora_Strutils; using namespace Pandora_Strutils;
#define PATH_SIZE _MAX_PATH+1 #define PATH_SIZE _MAX_PATH+1
#define PANDORA_VERSION ("2.0(Build 080610)") #define PANDORA_VERSION ("2.0(Build 080610)")
string pandora_path; string pandora_path;
string pandora_dir; string pandora_dir;
bool pandora_debug; bool pandora_debug;
string pandora_version = PANDORA_VERSION; string pandora_version = PANDORA_VERSION;
/** /**
* Parses a string and initialize the key and the value. * Parses a string and initialize the key and the value.
* *
* The string should be in the format: * The string should be in the format:
* - <code>key value</code> * - <code>key value</code>
* - <code>key "value with blankspaces"</code> * - <code>key "value with blankspaces"</code>
*/ */
void void
Key_Value::parseLine (string str) { Key_Value::parseLine (string str) {
unsigned int pos; unsigned int pos;
list<string> tokens; list<string> tokens;
list<string>::iterator iter; list<string>::iterator iter;
string trimmedstr; string trimmedstr;
trimmedstr = trim (str); trimmedstr = trim (str);
/* Check if the string has " */ /* Check if the string has " */
pos = trimmedstr.find ("\""); pos = trimmedstr.find ("\"");
if (pos == string::npos) { if (pos == string::npos) {
stringtok (tokens, trimmedstr, " \t"); stringtok (tokens, trimmedstr, " \t");
} else { } else {
stringtok (tokens, trimmedstr, "\""); stringtok (tokens, trimmedstr, "\"");
} }
/* Pick the first and the last value of the token list */ /* Pick the first and the last value of the token list */
iter = tokens.begin (); iter = tokens.begin ();
key = trim (*iter); key = trim (*iter);
transform (key.begin(), key.end(), key.begin(), (int(*)(int)) tolower); transform (key.begin(), key.end(), key.begin(), (int(*)(int)) tolower);
iter = tokens.end (); iter = tokens.end ();
iter--; iter--;
/* Check if the line has only one token */ /* Check if the line has only one token */
if (iter != tokens.begin ()) { if (iter != tokens.begin ()) {
value = trim (*iter); value = trim (*iter);
} else { } else {
value = ""; value = "";
} }
} }
/** /**
* Get the key of the object. * Get the key of the object.
* *
* @return The key * @return The key
*/ */
string string
Key_Value::getKey () { Key_Value::getKey () {
return key; return key;
} }
/** /**
* Get the value of the object. * Get the value of the object.
* *
* @return The value * @return The value
*/ */
string string
Key_Value::getValue () { Key_Value::getValue () {
return value; return value;
} }
void void
pandoraWriteLog (string filename, string line) { pandoraWriteLog (string filename, string line) {
string buffer; string buffer;
char str_time[25]; char str_time[25];
FILE *file; FILE *file;
string filepath; string filepath;
SYSTEMTIME st; SYSTEMTIME st;
GetSystemTime(&st); GetSystemTime(&st);
sprintf (str_time, "%d-%02d-%02d %02d:%02d:%02d ", st.wYear, st.wMonth, st.wDay, sprintf (str_time, "%d-%02d-%02d %02d:%02d:%02d ", st.wYear, st.wMonth, st.wDay,
st.wHour, st.wMinute, st.wSecond); st.wHour, st.wMinute, st.wSecond);
buffer = (char *) str_time; buffer = (char *) str_time;
buffer += line; buffer += line;
filepath = pandora_dir + filename; filepath = pandora_dir + filename;
file = fopen (filepath.c_str (), "a+"); file = fopen (filepath.c_str (), "a+");
if (file != NULL) { if (file != NULL) {
fprintf (file, "%s\n", buffer.c_str ()); fprintf (file, "%s\n", buffer.c_str ());
fclose (file); fclose (file);
} }
} }
/** /**
* Write a message in the log file. * Write a message in the log file.
* *
* The log file is used to write the output of errors and problems of the * The log file is used to write the output of errors and problems of the
* agent. * agent.
* *
* @param format String output format (like printf). * @param format String output format (like printf).
* @param ... Variable argument list * @param ... Variable argument list
*/ */
void void
Pandora::pandoraLog (char *format, ...) { Pandora::pandoraLog (char *format, ...) {
va_list args; va_list args;
char msg[5000]; char msg[5000];
va_start (args, format); va_start (args, format);
vsprintf (msg, format, args); vsprintf (msg, format, args);
va_end (args); va_end (args);
pandoraWriteLog ("pandora_agent.log", (char *) msg); pandoraWriteLog ("pandora_agent.log", (char *) msg);
} }
/** /**
* Write a message in the debug file. * Write a message in the debug file.
* *
* The log file is used to write the output of debugging information of the * The log file is used to write the output of debugging information of the
* agent. * agent.
* *
* @param format String output format. * @param format String output format.
* @param ... Variable argument list * @param ... Variable argument list
*/ */
void void
Pandora::pandoraDebug (char *format, ...) { Pandora::pandoraDebug (char *format, ...) {
if (pandora_debug) { if (pandora_debug) {
va_list args; va_list args;
char msg[5000]; char msg[5000];
va_start (args, format); va_start (args, format);
vsprintf (msg, format, args); vsprintf (msg, format, args);
va_end (args); va_end (args);
pandoraWriteLog ("pandora_debug.log", (char *) msg); pandoraWriteLog ("pandora_debug.log", (char *) msg);
} }
return; return;
} }
/** /**
* Secure free of a pointer. * Secure free of a pointer.
* *
* @param pointer pointer to free. * @param pointer pointer to free.
*/ */
void void
Pandora::pandoraFree (void * pointer) { Pandora::pandoraFree (void * pointer) {
if (pointer != NULL) if (pointer != NULL)
free (pointer); free (pointer);
return; return;
} }
/** /**
* Set the installation directory of the application. * Set the installation directory of the application.
* *
* This directory is the path to the directory which holds * This directory is the path to the directory which holds
* the binary file. * the binary file.
* *
* @param dir The path to the directory. * @param dir The path to the directory.
* *
* @see getPandoraInstallDir * @see getPandoraInstallDir
*/ */
void void
Pandora::setPandoraInstallDir (string dir) { Pandora::setPandoraInstallDir (string dir) {
pandora_dir = dir; pandora_dir = dir;
} }
/** /**
* Get the installation directory of the application. * Get the installation directory of the application.
* *
* This directory is the path to the directory which holds * This directory is the path to the directory which holds
* the binary file. * the binary file.
* *
* @return The path to the directory. * @return The path to the directory.
* *
* @see setPandoraInstallDir * @see setPandoraInstallDir
*/ */
string string
Pandora::getPandoraInstallDir () { Pandora::getPandoraInstallDir () {
return pandora_dir; return pandora_dir;
} }
/** /**
* Set the installation path of the application. * Set the installation path of the application.
* *
* This the complete path to the binary file. * This the complete path to the binary file.
* *
* @param path The path to the binary file. * @param path The path to the binary file.
* *
* @see getPandoraInstallPath * @see getPandoraInstallPath
*/ */
void void
Pandora::setPandoraInstallPath (string path) { Pandora::setPandoraInstallPath (string path) {
pandora_path = path; pandora_path = path;
} }
/** /**
* Get the installation path of the application. * Get the installation path of the application.
* *
* This the complete path to the binary file. * This the complete path to the binary file.
* *
* @return The path. * @return The path.
* *
* @see setPandoraInstallPath * @see setPandoraInstallPath
*/ */
string string
Pandora::getPandoraInstallPath () { Pandora::getPandoraInstallPath () {
return pandora_path; return pandora_path;
} }
/** /**
* Set the debug flag. * Set the debug flag.
* *
* If the flag is true output wil be generated and XML files will not be deleted. * If the flag is true output wil be generated and XML files will not be deleted.
* *
* @param dbg Turns the debug flag on/off. * @param dbg Turns the debug flag on/off.
* *
* @see getPandoraDebug * @see getPandoraDebug
* @see pandoraDebug * @see pandoraDebug
*/ */
void void
Pandora::setPandoraDebug (bool dbg) { Pandora::setPandoraDebug (bool dbg) {
pandora_debug = dbg; pandora_debug = dbg;
} }
/** /**
* Get the debug flag value. * Get the debug flag value.
* *
* If the flag is truee output wil be generated and XML files will not be deleted. * If the flag is truee output wil be generated and XML files will not be deleted.
* *
* @see setPandoraDebug * @see setPandoraDebug
* @see pandoraDebug * @see pandoraDebug
*/ */
bool bool
Pandora::getPandoraDebug () { Pandora::getPandoraDebug () {
return pandora_debug; return pandora_debug;
} }
/** /**
* Get the version of the agent. * Get the version of the agent.
* *
* @return The version. * @return The version.
*/ */
string string
Pandora::getPandoraAgentVersion () { Pandora::getPandoraAgentVersion () {
return pandora_version; return pandora_version;
} }

View File

@ -39,24 +39,31 @@ using namespace Pandora_Modules;
using namespace Pandora_Strutils; using namespace Pandora_Strutils;
string enabled_values[] = {"enabled", "1", "on", "yes", "si", "", "ok", ""}; string enabled_values[] = {"enabled", "1", "on", "yes", "si", "", "ok", ""};
Pandora_Windows_Service::Pandora_Windows_Service ()
: Windows_Service (NULL, NULL, NULL) {
this->setInitFunction ((void (Windows_Service::*) ())
&Pandora_Windows_Service::pandora_init);
this->setRunFunction ((void (Windows_Service::*) ())
&Pandora_Windows_Service::pandora_run);
this->started = false;
}
/** /**
* Creates a new Pandora_Windows_Service. * Set Pandora service Windows properties.
* *
* @param svc_name Internal service name * @param svc_name Internal service name
* @param svc_display_name Service name that will appear in the * @param svc_display_name Service name that will appear in the
* Windows service administration tool. * Windows service administration tool.
* @param svc_description Long description of the service. * @param svc_description Long description of the service.
*/ */
Pandora_Windows_Service::Pandora_Windows_Service (const char * svc_name, void
const char * svc_display_name, Pandora_Windows_Service::setValues (const char * svc_name,
const char * svc_description) const char * svc_display_name,
: Windows_Service (svc_name, svc_display_name, svc_description) { const char * svc_description) {
this->setInitFunction ((void (Windows_Service::*) ()) this->service_name = (char *) svc_name;
&Pandora_Windows_Service::pandora_init); this->service_display_name = (char *) svc_display_name;
this->setRunFunction ((void (Windows_Service::*) ()) this->service_description = (char *) svc_description;
&Pandora_Windows_Service::pandora_run);
execution_number = 0; execution_number = 0;
this->modules = NULL; this->modules = NULL;
this->conf = NULL; this->conf = NULL;
@ -78,6 +85,23 @@ Pandora_Windows_Service::~Pandora_Windows_Service () {
} }
pandoraLog ("Pandora agent stopped"); pandoraLog ("Pandora agent stopped");
} }
Pandora_Windows_Service *
Pandora_Windows_Service::getInstance () {
static Pandora_Windows_Service *service = NULL;
if (service != NULL)
return service;
service = new Pandora_Windows_Service ();
return service;
}
void
Pandora_Windows_Service::start () {
this->started = true;
}
bool bool
is_enabled (string value) { is_enabled (string value) {
@ -161,7 +185,7 @@ Pandora_Windows_Service::getXmlHeader () {
// Get current time // Get current time
ctime = time(0); ctime = time(0);
ctime_tm = localtime(&ctime); ctime_tm = localtime(&ctime);
sprintf (timestamp, "%d-%02d-%02d %02d:%02d:%02d", ctime_tm->tm_year + 1900, sprintf (timestamp, "%d-%02d-%02d %02d:%02d:%02d", ctime_tm->tm_year + 1900,
ctime_tm->tm_mon + 1, ctime_tm->tm_mday, ctime_tm->tm_hour, ctime_tm->tm_mon + 1, ctime_tm->tm_mday, ctime_tm->tm_hour,
@ -589,7 +613,7 @@ Pandora_Windows_Service::checkConfig () {
Pandora_File::removeFile (tmp); Pandora_File::removeFile (tmp);
/* Save new configuration */ /* Save new configuration */
Pandora_File::writeBinFile (conf_file, conf_str, conf_size); Pandora_File::writeBinFile (conf_file, conf_str, conf_size);
} catch (...) { } catch (...) {
pandoraDebug("Pandora_Windows_Service::checkConfig: Error retrieving configuration file from server"); pandoraDebug("Pandora_Windows_Service::checkConfig: Error retrieving configuration file from server");
if (conf_str != NULL) { if (conf_str != NULL) {
delete[] conf_str; delete[] conf_str;
@ -602,17 +626,95 @@ Pandora_Windows_Service::checkConfig () {
/* Reload configuration */ /* Reload configuration */
this->pandora_init (); this->pandora_init ();
} }
void
Pandora_Windows_Service::sendXml (Pandora_Module_List *modules) {
TiXmlDeclaration *decl;
TiXmlDocument *doc;
TiXmlElement *local_xml, *agent;
string xml_filename, random_integer;
string tmp_filename, tmp_filepath;
string encoding;
bool saved;
static HANDLE mutex = 0;
if (mutex == 0) {
mutex = CreateMutex (NULL, FALSE, NULL);
}
/* Wait for the mutex to be opened */
WaitForSingleObject (mutex, INFINITE);
pandoraLog ("aasdfasdf");
agent = getXmlHeader ();
if (modules != NULL) {
modules->goFirst ();
while (! modules->isLast ()) {
Pandora_Module *module;
module = modules->getCurrentValue ();
local_xml = module->getXml ();
if (local_xml != NULL) {
agent->InsertEndChild (*local_xml);
delete local_xml;
}
modules->goNext ();
}
}
/* Generate temporal filename */
random_integer = inttostr (rand());
tmp_filename = conf->getValue ("agent_name");
if (tmp_filename == "") {
tmp_filename = Pandora_Windows_Info::getSystemName ();
}
tmp_filename += "." + random_integer + ".data";
xml_filename = conf->getValue ("temporal");
if (xml_filename[xml_filename.length () - 1] != '\\') {
xml_filename += "\\";
}
tmp_filepath = xml_filename + tmp_filename;
/* Copy the XML to temporal file */
encoding = conf->getValue ("encoding");
if (encoding == "") {
encoding = "ISO-8859-1";
}
pandoraDebug ("Copying XML on %s", tmp_filepath.c_str ());
decl = new TiXmlDeclaration( "1.0", encoding.c_str(), "" );
doc = new TiXmlDocument (tmp_filepath);
doc->InsertEndChild (*decl);
doc->InsertEndChild (*agent);
saved = doc->SaveFile();
delete doc;
delete agent;
if (!saved) {
pandoraLog ("Error when saving the XML in %s",
tmp_filepath.c_str ());
return;
}
/* Only send if debug is not activated */
if (getPandoraDebug () == false) {
this->copyDataFile (tmp_filename);
try {
Pandora_File::removeFile (tmp_filepath);
} catch (Pandora_File::Delete_Error e) {
}
}
ReleaseMutex (mutex);
}
void void
Pandora_Windows_Service::pandora_run () { Pandora_Windows_Service::pandora_run () {
TiXmlDeclaration *decl;
TiXmlDocument *doc;
TiXmlElement *local_xml, *agent;
string xml_filename, random_integer;
string tmp_filename, tmp_filepath;
string encoding;
bool saved;
pandoraDebug ("Run begin"); pandoraDebug ("Run begin");
/* Check for configuration changes */ /* Check for configuration changes */
@ -635,74 +737,12 @@ Pandora_Windows_Service::pandora_run () {
} }
} }
this->elapsed_transfer_time += interval; this->elapsed_transfer_time += this->interval;
if (this->elapsed_transfer_time >= this->transfer_interval) { if (this->elapsed_transfer_time >= this->transfer_interval) {
agent = getXmlHeader (); this->elapsed_transfer_time = 0;
if (this->modules != NULL) { this->sendXml (this->modules);
this->modules->goFirst ();
while (! this->modules->isLast ()) {
Pandora_Module *module;
module = this->modules->getCurrentValue ();
local_xml = module->getXml ();
if (local_xml != NULL) {
agent->InsertEndChild (*local_xml);
delete local_xml;
}
this->modules->goNext ();
}
}
this->elapsed_transfer_time = 0;
/* Generate temporal filename */
random_integer = inttostr (rand());
tmp_filename = conf->getValue ("agent_name");
if (tmp_filename == "") {
tmp_filename = Pandora_Windows_Info::getSystemName ();
}
tmp_filename += "." + random_integer + ".data";
xml_filename = conf->getValue ("temporal");
if (xml_filename[xml_filename.length () - 1] != '\\') {
xml_filename += "\\";
}
tmp_filepath = xml_filename + tmp_filename;
/* Copy the XML to temporal file */
encoding = conf->getValue ("encoding");
if (encoding == "") {
encoding = "ISO-8859-1";
}
pandoraDebug ("Copying XML on %s", tmp_filepath.c_str ());
decl = new TiXmlDeclaration( "1.0", encoding.c_str(), "" );
doc = new TiXmlDocument (tmp_filepath);
doc->InsertEndChild (*decl);
doc->InsertEndChild (*agent);
saved = doc->SaveFile();
delete doc;
delete agent;
if (!saved) {
pandoraLog ("Error when saving the XML in %s",
tmp_filepath.c_str ());
return;
}
/* Only send if debug is not activated */
if (getPandoraDebug () == false) {
this->copyDataFile (tmp_filename);
try {
Pandora_File::removeFile (tmp_filepath);
} catch (Pandora_File::Delete_Error e) {
}
}
} }
/* Get the interval value (in minutes) */ /* Get the interval value (in minutes) */

View File

@ -43,7 +43,8 @@ namespace Pandora {
string agent_name; string agent_name;
long interval; long interval;
long elapsed_transfer_time; long elapsed_transfer_time;
long transfer_interval; long transfer_interval;
bool started;
TiXmlElement *getXmlHeader (); TiXmlElement *getXmlHeader ();
void copyDataFile (string filename); void copyDataFile (string filename);
@ -58,15 +59,23 @@ namespace Pandora {
void recvDataFile (string filename); void recvDataFile (string filename);
void recvTentacleDataFile (string host, void recvTentacleDataFile (string host,
string filename); string filename);
void checkConfig (); void checkConfig ();
Pandora_Windows_Service ();
public: public:
void pandora_run (); void pandora_run ();
void pandora_init (); void pandora_init ();
public: public:
Pandora_Windows_Service (const char * svc_name, static Pandora_Windows_Service *getInstance ();
const char * svc_display_name,
const char * svc_description); ~Pandora_Windows_Service ();
~Pandora_Windows_Service ();
void setValues (const char *svc_name,
const char *svc_display_name,
const char *svc_description);
void start ();
void sendXml (Pandora_Module_List *modules);
}; };
} }

View File

@ -64,7 +64,7 @@ Pandora_Wmi::isProcessRunning (string process_name) {
query = "SELECT * FROM Win32_Process WHERE Name=\"" + process_name + "\""; query = "SELECT * FROM Win32_Process WHERE Name=\"" + process_name + "\"";
try { try {
dhCheck (dhGetObject (getWmiStr (L"."), NULL, &wmi_svc)); dhCheck (dhGetObject (getWmiStr (L"."), NULL, &wmi_svc));
dhCheck (dhGetValue (L"%o", &quickfixes, wmi_svc, dhCheck (dhGetValue (L"%o", &quickfixes, wmi_svc,
L".ExecQuery(%T)", L".ExecQuery(%T)",
@ -99,7 +99,7 @@ Pandora_Wmi::isServiceRunning (string service_name) {
query = "SELECT * FROM Win32_Service WHERE Name = \"" + service_name + "\""; query = "SELECT * FROM Win32_Service WHERE Name = \"" + service_name + "\"";
try { try {
dhCheck (dhGetObject (getWmiStr (L"."), NULL, &wmi_svc)); dhCheck (dhGetObject (getWmiStr (L"."), NULL, &wmi_svc));
dhCheck (dhGetValue (L"%o", &quickfixes, wmi_svc, dhCheck (dhGetValue (L"%o", &quickfixes, wmi_svc,
L".ExecQuery(%T)", L".ExecQuery(%T)",

View File

@ -35,10 +35,11 @@
* Notice: A program should have only one object of this class. * Notice: A program should have only one object of this class.
*/ */
class Windows_Service { class Windows_Service {
private: protected:
char *service_name; char *service_name;
char *service_display_name; char *service_display_name;
char *service_description; char *service_description;
private:
HANDLE stop_event; HANDLE stop_event;
int sleep_time; int sleep_time;
SC_HANDLE sc_service; SC_HANDLE sc_service;