source: nscp/service/NSClient++.cpp @ 29ff7e1

0.4.10.4.2
Last change on this file since 29ff7e1 was 29ff7e1, checked in by Michael Medin <michael@…>, 10 months ago
  • Fixed issue with performance data overflowing 32-bit integers (#550)
  • Fixed issue with CheckUptime? and time rendering being wrong (#549)
  • Property mode set to 100644
File size: 48.7 KB
Line 
1///////////////////////////////////////////////////////////////////////////
2// NSClient++ Base Service
3//
4// Copyright (c) 2004 MySolutions NORDIC (http://www.medin.name)
5//
6// Date: 2004-03-13
7// Author: Michael Medin (michael@medin.name)
8//
9// Part of this file is based on work by Bruno Vais (bvais@usa.net)
10//
11// This software is provided "AS IS", without a warranty of any kind.
12// You are free to use/modify this code but leave this header intact.
13//
14//////////////////////////////////////////////////////////////////////////
15#include "StdAfx.h"
16#include "NSClient++.h"
17#include <settings/settings_core.hpp>
18#include <charEx.h>
19#include <config.h>
20#ifdef WIN32
21#include <Userenv.h>
22#include <Lmcons.h>
23#endif
24#include "core_api.h"
25#include "../helpers/settings_manager/settings_manager_impl.h"
26#include <settings/macros.h>
27#include "simple_client.hpp"
28#include "settings_client.hpp"
29#include "service_manager.hpp"
30#include <nscapi/functions.hpp>
31
32#include <settings/client/settings_client.hpp>
33#include "cli_parser.hpp"
34#include "../version.hpp"
35
36#include <config.h>
37
38#ifdef WIN32
39#include <com_helpers.hpp>
40com_helper::initialize_com com_helper_;
41#endif
42
43
44#ifdef USE_BREAKPAD
45#include <breakpad/exception_handler_win32.hpp>
46// Used for breakpad crash handling
47static ExceptionManager *g_exception_manager = NULL;
48#endif
49
50NSClient mainClient;    // Global core instance.
51
52#define LOG_CRITICAL_CORE(msg) { nsclient::logging::logger::get_logger()->fatal(__FILE__, __LINE__, msg);}
53#define LOG_CRITICAL_CORE_STD(msg) LOG_CRITICAL_CORE(std::wstring(msg))
54#define LOG_ERROR_CORE(msg) { nsclient::logging::logger::get_logger()->error(__FILE__, __LINE__, msg);}
55#define LOG_ERROR_CORE_STD(msg) LOG_ERROR_CORE(std::wstring(msg))
56#define LOG_INFO_CORE(msg) { nsclient::logging::logger::get_logger()->info(__FILE__, __LINE__, msg);}
57#define LOG_INFO_CORE_STD(msg) LOG_INFO_CORE(std::wstring(msg))
58#define LOG_DEBUG_CORE(msg) { nsclient::logging::logger::get_logger()->debug(__FILE__, __LINE__, msg);}
59#define LOG_DEBUG_CORE_STD(msg) LOG_DEBUG_CORE(std::wstring(msg))
60
61/**
62 * START OF Tray starter MERGE HELPER
63 */
64class tray_starter {
65        struct start_block {
66                std::wstring cmd;
67                std::wstring cmd_line;
68                DWORD sessionId;
69        };
70
71public:
72        static LPVOID init(DWORD dwSessionId, std::wstring exe, std::wstring cmdline) {
73                start_block *sb = new start_block;
74                sb->cmd = exe;
75                sb->cmd_line = cmdline;
76                sb->sessionId = dwSessionId;
77                return sb;
78        }
79        DWORD threadProc(LPVOID lpParameter) {
80#ifdef WIN32
81                start_block* param = static_cast<start_block*>(lpParameter);
82                DWORD dwSessionId = param->sessionId;
83                std::wstring cmd = param->cmd;
84                std::wstring cmdline = param->cmd_line;
85                delete param;
86                for (int i=0;i<10;i++) {
87                        Sleep(1000);
88                        if (startTrayHelper(dwSessionId, cmd, cmdline, false))
89                                break;
90                }
91#endif
92                return 0;
93        }
94
95        static bool start(std::wstring command, unsigned long  dwSessionId) {
96                std::wstring cmdln = _T("\"") + command + _T("\" -channel __") + strEx::itos(dwSessionId) + _T("__");
97                return tray_starter::startTrayHelper(dwSessionId, command, cmdln);
98        }
99
100        static bool startTrayHelper(unsigned long dwSessionId, std::wstring exe, std::wstring cmdline, bool startThread = true) {
101//              HANDLE hToken = NULL;
102//              if (!remote_processes::GetSessionUserToken(dwSessionId, &hToken)) {
103//                      LOG_ERROR_STD(_T("Failed to query user token: ") + error::lookup::last_error());
104//                      return false;
105//              } else {
106//                      STARTUPINFO          StartUPInfo;
107//                      PROCESS_INFORMATION  ProcessInfo;
108//
109//                      ZeroMemory(&StartUPInfo,sizeof(STARTUPINFO));
110//                      ZeroMemory(&ProcessInfo,sizeof(PROCESS_INFORMATION));
111//                      StartUPInfo.wShowWindow = SW_HIDE;
112//                      StartUPInfo.lpDesktop = L"Winsta0\\Default";
113//                      StartUPInfo.cb = sizeof(STARTUPINFO);
114//
115//                      wchar_t *buffer = new wchar_t[cmdline.size()+10];
116//                      wcscpy(buffer, cmdline.c_str());
117//                      LOG_MESSAGE_STD(_T("Running: ") + exe);
118//                      LOG_MESSAGE_STD(_T("Running: ") + cmdline);
119//
120//                      LPVOID pEnv =NULL;
121//                      DWORD dwCreationFlags = CREATE_NO_WINDOW; //0; //DETACHED_PROCESS
122//
123//                      if(CreateEnvironmentBlock(&pEnv,hToken,TRUE)) {
124//                              dwCreationFlags|=CREATE_UNICODE_ENVIRONMENT;
125//                      } else {
126//                              LOG_ERROR_STD(_T("Failed to create enviornment: ") + error::lookup::last_error());
127//                              pEnv=NULL;
128//                      }
129//                      /*
130//                      LOG_ERROR_STD(_T("Impersonating user: "));
131//                      if (!ImpersonateLoggedOnUser(hToken)) {
132//                              LOG_ERROR_STD(_T("Failed to impersonate the user: ") + error::lookup::last_error());
133//                      }
134//
135//                      wchar_t pszUname[UNLEN + 1];
136//                      ZeroMemory(pszUname,sizeof(pszUname));
137//                      DWORD dwSize = UNLEN;
138//                      if (!GetUserName(pszUname,&dwSize)) {
139//                              DWORD dwErr = GetLastError();
140//                              if (!RevertToSelf())
141//                                      LOG_ERROR_STD(_T("Failed to revert to self: ") + error::lookup::last_error());
142//                              LOG_ERROR_STD(_T("Failed to get username: ") + error::format::from_system(dwErr));
143//                              return false;
144//                      }
145//                     
146//
147//                      PROFILEINFO info;
148//                      info.dwSize = sizeof(PROFILEINFO);
149//                      info.lpUserName = pszUname;
150//                      if (!LoadUserProfile(hToken, &info)) {
151//                              DWORD dwErr = GetLastError();
152//                              if (!RevertToSelf())
153//                                      LOG_ERROR_STD(_T("Failed to revert to self: ") + error::lookup::last_error());
154//                              LOG_ERROR_STD(_T("Failed to get username: ") + error::format::from_system(dwErr));
155//                              return false;
156//                      }
157//                      */
158//                      if (!CreateProcessAsUser(hToken, exe.c_str(), buffer, NULL, NULL, FALSE, dwCreationFlags, pEnv, NULL, &StartUPInfo, &ProcessInfo)) {
159//                              DWORD dwErr = GetLastError();
160//                              delete [] buffer;
161//                              /*
162//                              if (!RevertToSelf()) {
163//                                      LOG_ERROR_STD(_T("Failed to revert to self: ") + error::lookup::last_error());
164//                              }
165//                              */
166//                              if (startThread && dwErr == ERROR_PIPE_NOT_CONNECTED) {
167//                                      LOG_MESSAGE(_T("Failed to start trayhelper: starting a background thread to do it instead..."));
168//                                      Thread<tray_starter> *pThread = new Thread<tray_starter>(_T("tray-starter-thread"));
169//                                      pThread->createThread(tray_starter::init(dwSessionId, exe, cmdline));
170//                                      return false;
171//                              } else if (dwErr == ERROR_PIPE_NOT_CONNECTED) {
172//                                      LOG_ERROR_STD(_T("Thread failed to start trayhelper (will try again): ") + error::format::from_system(dwErr));
173//                                      return false;
174//                              } else {
175//                                      LOG_ERROR_STD(_T("Failed to start trayhelper: ") + error::format::from_system(dwErr));
176//                                      return true;
177//                              }
178//                      } else {
179//                              delete [] buffer;
180//                              /*
181//                              if (!RevertToSelf()) {
182//                                      LOG_ERROR_STD(_T("Failed to revert to self: ") + error::lookup::last_error());
183//                              }
184//                              */
185//                              LOG_MESSAGE_STD(_T("Started tray in other user session: ") + strEx::itos(dwSessionId));
186//                      }
187//
188//
189//                      CloseHandle(hToken);
190//                      return true;
191//              }
192                return false;
193        }
194};
195
196/**
197 * End of class tray started (MERGE HELP)
198 */
199
200bool is_module(boost::filesystem::wpath file )
201{
202#ifdef WIN32
203        return boost::ends_with(file.string(), _T(".dll"));
204#else
205        return boost::ends_with(file.string(), _T(".so"));
206#endif
207}
208/**
209 * Application startup point
210 *
211 * @param argc Argument count
212 * @param argv[] Argument array
213 * @param envp[] Environment array
214 * @return exit status
215 */
216int nscp_main(int argc, wchar_t* argv[]);
217
218#ifdef WIN32
219int wmain(int argc, wchar_t* argv[], wchar_t* envp[]) { return nscp_main(argc, argv); }
220#else
221int main(int argc, char* argv[]) {
222        wchar_t **wargv = new wchar_t*[argc];
223        for (int i=0;i<argc;i++) {
224                std::wstring s = to_wstring(argv[i]);
225                wargv[i] = new wchar_t[s.length()+10];
226                wcscpy(wargv[i], s.c_str());
227        }
228        int ret = nscp_main(argc, wargv);
229        for (int i=0;i<argc;i++) {
230                delete [] wargv[i];
231        }
232        delete [] wargv;
233        return ret;
234}
235#endif
236
237int nscp_main(int argc, wchar_t* argv[])
238{
239        srand( (unsigned)time( NULL ) );
240        cli_parser parser(&mainClient);
241        return parser.parse(argc, argv);
242}
243
244std::list<std::wstring> NSClientT::list_commands() {
245        return commands_.list();
246}
247
248bool contains_plugin(NSClientT::plugin_alias_list_type &ret, std::wstring alias, std::wstring plugin) {
249        std::pair<std::wstring,std::wstring> v;
250        BOOST_FOREACH(v, ret.equal_range(alias)) {
251                if (v.second == plugin)
252                        return true;
253        }
254        return false;
255}
256
257NSClientT::NSClientT()
258        : enable_shared_session_(false)
259        , next_plugin_id_(0)
260        , service_name_(DEFAULT_SERVICE_NAME)
261{
262                nsclient::logging::logger::startup();
263}
264
265NSClientT::~NSClientT() {
266        try {
267                nsclient::logging::logger::destroy();
268        } catch(...) {
269                std::wcerr << _T("UNknown exception raised: When destroying logger") << std::endl;
270        }
271}
272
273
274NSClientT::plugin_alias_list_type NSClientT::find_all_plugins(bool active) {
275        plugin_alias_list_type ret;
276
277        settings::string_list list = settings_manager::get_settings()->get_keys(MAIN_MODULES_SECTION);
278        BOOST_FOREACH(std::wstring plugin, list) {
279                std::wstring alias;
280                try {
281                        alias = settings_manager::get_settings()->get_string(MAIN_MODULES_SECTION, plugin);
282                } catch (settings::settings_exception e) {
283                        LOG_DEBUG_CORE_STD(_T("Exception looking for module: ") + e.getMessage());
284                }
285                if (plugin == _T("enabled") || plugin == _T("1")) {
286                        plugin = alias;
287                        alias = _T("");
288                } else if (alias == _T("enabled") || alias == _T("1")) {
289                                alias = _T("");
290                } else if ((active && plugin == _T("disabled")) || (active && alias == _T("disabled")))
291                        continue;
292                 else if ((active && plugin == _T("0")) || (active && alias == _T("0")))
293                        continue;
294                else if (plugin == _T("disabled") || plugin == _T("0")) {
295                        plugin = alias;
296                        alias = _T("");
297                } else if (alias == _T("disabled") || alias == _T("0")) {
298                        alias = _T("");
299                }
300                if (!alias.empty()) {
301                        std::wstring tmp = plugin;
302                        plugin = alias;
303                        alias = tmp;
304                }
305                if (alias.empty()) {
306                        LOG_DEBUG_CORE_STD(_T("Found: ") + plugin);
307                } else {
308                        LOG_DEBUG_CORE_STD(_T("Found: ") + plugin + _T(" as ") + alias);
309                }
310                if (plugin.length() > 4 && plugin.substr(plugin.length()-4) == _T(".dll"))
311                        plugin = plugin.substr(0, plugin.length()-4);
312                ret.insert(plugin_alias_list_type::value_type(alias, plugin));
313        }
314        if (!active) {
315                boost::filesystem::wpath pluginPath = expand_path(_T("${module-path}"));
316                boost::filesystem::wdirectory_iterator end_itr; // default construction yields past-the-end
317                for ( boost::filesystem::wdirectory_iterator itr( pluginPath ); itr != end_itr; ++itr ) {
318                        if ( !is_directory(itr->status()) ) {
319                                boost::filesystem::wpath file= itr->leaf();
320                                if (is_module(pluginPath  / file) && !contains_plugin(ret, _T(""), file.string()))
321                                        ret.insert(plugin_alias_list_type::value_type(_T(""), file.string()));
322                        }
323                }
324        }
325        return ret;
326}
327
328void NSClientT::preboot_load_all_plugin_files() {
329        boost::filesystem::wpath pluginPath;
330        {
331                try {
332                        pluginPath = expand_path(_T("${module-path}"));
333                } catch (std::exception &e) {
334                        LOG_CRITICAL_CORE_STD(_T("Failed to load plugins: ") + to_wstring(e.what()) + _T(" for ") + expand_path(_T("${module-path}")));
335                        return;
336                }
337                plugin_alias_list_type plugins = find_all_plugins(false);
338                std::pair<std::wstring,std::wstring> v;
339
340                BOOST_FOREACH(v, plugins) {
341                        try {
342                                addPlugin(pluginPath / v.second, v.first);
343                        } catch (const NSPluginException &e) {
344                                if (e.file_.find(_T("FileLogger")) != std::wstring::npos) {
345                                        LOG_DEBUG_CORE_STD(_T("Failed to register plugin: ") + e.wwhat());
346                                } else {
347                                        LOG_ERROR_CORE(_T("Failed to register plugin: ") + e.wwhat());
348                                }
349                        } catch (...) {
350                                LOG_CRITICAL_CORE_STD(_T("Failed to register plugin key: ") + v.second);
351                        }
352                }
353        }
354}
355
356//////////////////////////////////////////////////////////////////////////
357// Service functions
358
359struct nscp_settings_provider : public settings_manager::provider_interface {
360        virtual std::wstring expand_path(std::wstring file) {
361                return mainClient.expand_path(file);
362        }
363        std::wstring get_data(std::wstring key) {
364                // TODO
365                return _T("");
366        }
367};
368
369
370nscp_settings_provider provider;
371
372namespace sh = nscapi::settings_helper;
373
374/**
375 * Initialize the program
376 * @param boot true if we shall boot all plugins
377 * @param attachIfPossible is true we will attach to a running instance.
378 * @return success
379 * @author mickem
380 */
381bool NSClientT::boot_init(std::wstring log_level) {
382        LOG_DEBUG_CORE(SERVICE_NAME _T(" Loading settings and logger..."));
383
384        if (!settings_manager::init_settings(&provider, context_)) {
385                return false;
386        }
387
388        nsclient::logging::logger::configure();
389        bool cli_overrides_log = !log_level.empty();
390        if (!log_level.empty())
391                nsclient::logging::logger::set_log_level(log_level);
392
393        LOG_INFO_CORE(SERVICE_NAME _T(" booting..."));
394        LOG_DEBUG_CORE(_T("Booted settings subsystem..."));
395        LOG_ERROR_CORE(_T("===> ") + strEx::itos_as_time(11171600000));
396
397        bool crash_submit = false;
398        bool crash_archive = false;
399        bool crash_restart = false;
400        std::wstring crash_url, crash_folder, crash_target;
401        try {
402
403                sh::settings_registry settings(settings_manager::get_proxy());
404
405                settings.add_path()
406                        (_T("/modules"),                        _T("MODULES"), _T("A list of modules."))
407                        ;
408
409                settings.add_path_to_settings()
410                        (_T("log"),                     _T("LOG SETTINGS"), _T("Section for configuring the log handling."))
411                        (_T("shared session"),  _T("SHRED SESSION"), _T("Section for configuring the shared session."))
412                        (_T("crash"),                   _T("CRASH HANDLER"), _T("Section for configuring the crash handler."))
413                        ;
414
415                settings.add_key_to_settings(_T("log"))
416                        (_T("level"), sh::wstring_key(&log_level, _T("info")),
417                        _T("LOG LEVEL"), _T("Log level to use. Avalible levels are error,warning,info,debug,trace"))
418                        ;
419
420                settings.add_key_to_settings(_T("shared session"))
421                        (_T("enabled"), sh::bool_key(&enable_shared_session_ , false),
422                        _T("LOG LEVEL"), _T("Log level to use"))
423                        ;
424
425                settings.add_key_to_settings(_T("crash"))
426                        (_T("submit"), sh::bool_key(&crash_submit, false),
427                        _T("SUBMIT CRASHREPORTS"), _T("Submit crash reports to nsclient.org (or your configured submission server)"))
428
429                        (_T("archive"), sh::bool_key(&crash_archive, true),
430                        _T("ARCHIVE CRASHREPORTS"), _T("Archive crash reports in the archive folder"))
431
432                        (_T("restart"), sh::bool_key(&crash_restart, true),
433                        _T("RESTART"), _T("Submit crash reports to nsclient.org (or your configured submission server)"))
434
435                        (_T("restart target"), sh::wstring_key(&crash_target, get_service_control().get_service_name()),
436                        _T("RESTART SERVICE NAME"), _T("The url to submit crash reports to"))
437
438                        (_T("submit url"), sh::wstring_key(&crash_url, CRASH_SUBMIT_URL),
439                        _T("SUBMISSION URL"), _T("The url to submit crash reports to"))
440
441                        (_T("archive folder"), sh::wpath_key(&crash_folder, CRASH_ARCHIVE_FOLDER),
442                        _T("CRASH ARCHIVE LOCATION"), _T("The folder to archive crash dumps in"))
443                        ;
444
445                settings.register_all();
446                settings.notify();
447
448        } catch (settings::settings_exception e) {
449                LOG_ERROR_CORE_STD(_T("Could not find settings: ") + e.getMessage());
450        }
451        if (!cli_overrides_log)
452                nsclient::logging::logger::set_log_level(log_level);
453
454#ifdef USE_BREAKPAD
455
456        if (!g_exception_manager) {
457                g_exception_manager = new ExceptionManager(false);
458
459                g_exception_manager->setup_app(to_wstring(APPLICATION_NAME), to_wstring(STRPRODUCTVER), to_wstring(STRPRODUCTDATE));
460
461                if (crash_restart) {
462                        LOG_DEBUG_CORE(_T("On crash: restart: ") + crash_target);
463                        g_exception_manager->setup_restart(crash_target);
464                }
465
466                bool crashHandling = false;
467                if (crash_submit) {
468                        g_exception_manager->setup_submit(false, crash_url);
469                        LOG_DEBUG_CORE(_T("Submitting crash dumps to central server: ") + crash_url);
470                        crashHandling = true;
471                }
472                if (crash_archive) {
473                        g_exception_manager->setup_archive(crash_folder);
474                        LOG_DEBUG_CORE(_T("Archiving crash dumps in: ") + crash_folder);
475                        crashHandling = true;
476                }
477                if (!crashHandling) {
478                        LOG_ERROR_CORE(_T("No crash handling configured"));
479                } else {
480                        g_exception_manager->StartMonitoring();
481                }
482        }
483#else
484        LOG_ERROR_CORE(_T("Warning Not compiled with google breakpad support!"));
485#endif
486
487
488        if (enable_shared_session_) {
489                LOG_INFO_CORE(_T("shared session not ported yet!..."));
490//              if (boot) {
491//                      LOG_INFO_CORE(_T("shared session not ported yet!..."));
492//                      try {
493//                              shared_server_.reset(new nsclient_session::shared_server_session(this));
494//                              if (!shared_server_->session_exists()) {
495//                                      shared_server_->create_new_session();
496//                              } else {
497//                                      LOG_ERROR_STD(_T("Session already exists cant create a new one!"));
498//                              }
499//                              startTrayIcons();
500//                      } catch (nsclient_session::session_exception e) {
501//                              LOG_ERROR_STD(_T("Failed to create new session: ") + e.what());
502//                              shared_server_.reset(NULL);
503//                      } catch (...) {
504//                              LOG_ERROR_STD(_T("Failed to create new session: Unknown exception"));
505//                              shared_server_.reset(NULL);
506//                      }
507//              } else {
508//                      LOG_INFO_CORE(_T("shared session not ported yet!..."));
509//                      try {
510//                              std::wstring id = _T("_attached_") + strEx::itos(GetCurrentProcessId()) + _T("_");
511//                              shared_client_.reset(new nsclient_session::shared_client_session(id, this));
512//                              if (shared_client_->session_exists()) {
513//                                      shared_client_->attach_to_session(id);
514//                              } else {
515//                                      LOG_ERROR_STD(_T("No session was found cant attach!"));
516//                              }
517//                              LOG_ERROR_STD(_T("Session is: ") + shared_client_->get_client_id());
518//                      } catch (nsclient_session::session_exception e) {
519//                              LOG_ERROR_STD(_T("Failed to attach to session: ") + e.what());
520//                              shared_client_.reset(NULL);
521//                      } catch (...) {
522//                              LOG_ERROR_STD(_T("Failed to attach to session: Unknown exception"));
523//                              shared_client_.reset(NULL);
524//                      }
525//              }
526        }
527#ifdef WIN32
528        try {
529                com_helper_.initialize();
530        } catch (com_helper::com_exception e) {
531                LOG_ERROR_CORE_STD(_T("COM exception: ") + e.getMessage());
532                return false;
533        } catch (...) {
534                LOG_ERROR_CORE(_T("Unknown exception iniating COM..."));
535                return false;
536        }
537#endif
538        return true;
539}
540bool NSClientT::boot_load_all_plugins() {
541        LOG_DEBUG_CORE(_T("booting::loading plugins"));
542        try {
543                boost::filesystem::wpath pluginPath = expand_path(_T("${module-path}"));
544                plugin_alias_list_type plugins = find_all_plugins(true);
545                std::pair<std::wstring,std::wstring> v;
546                BOOST_FOREACH(v, plugins) {
547                        std::wstring file = NSCPlugin::get_plugin_file(v.second);
548                        std::wstring alias = v.first;
549//                      if (!alias.empty()) {
550//                              LOG_DEBUG_CORE_STD(_T("Processing plugin: ") + file + _T(" as ") + alias);
551//                      } else {
552//                              LOG_DEBUG_CORE_STD(_T("Processing plugin: ") + file);
553//                      }
554                        try {
555                                addPlugin(pluginPath / boost::filesystem::wpath(file), alias);
556                        } catch(const NSPluginException& e) {
557                                if (e.file_.find(_T("FileLogger")) != std::wstring::npos) {
558                                        LOG_DEBUG_CORE_STD(_T("Exception raised: '") + e.error_ + _T("' in module: ") + e.file_);
559                                } else {
560                                        LOG_ERROR_CORE_STD(_T("Exception raised: '") + e.error_ + _T("' in module: ") + e.file_);
561                                }
562                        } catch (std::exception e) {
563                                LOG_ERROR_CORE_STD(_T("exception loading plugin: ") + file + strEx::string_to_wstring(e.what()));
564                                return false;
565                        } catch (...) {
566                                LOG_ERROR_CORE_STD(_T("Unknown exception loading plugin: ") + file);
567                                return false;
568                        }
569                }
570        } catch (settings::settings_exception e) {
571                LOG_ERROR_CORE_STD(_T("Settings exception when loading modules: ") + e.getMessage());
572                return false;
573        } catch (...) {
574                LOG_ERROR_CORE_STD(_T("Unknown exception when loading plugins"));
575                return false;
576        }
577        return true;
578}
579
580bool NSClientT::boot_load_plugin(std::wstring plugin) {
581        try {
582                if (plugin.length() > 4 && plugin.substr(plugin.length()-4) == _T(".dll"))
583                        plugin = plugin.substr(0, plugin.length()-4);
584
585                std::wstring plugin_file = NSCPlugin::get_plugin_file(plugin);
586                boost::filesystem::wpath pluginPath = expand_path(_T("${module-path}"));
587                boost::filesystem::wpath file = pluginPath / plugin_file;
588                if (boost::filesystem::is_regular(file)) {
589                        plugin_type plugin = addPlugin(file, _T(""));
590                } else {
591                        LOG_ERROR_CORE_STD(_T("Failed to load: ") + std::wstring(plugin));
592                        return false;
593                }
594        } catch (const NSPluginException &e) {
595                LOG_ERROR_CORE_STD(_T("Module (") + e.file_ + _T(") was not found: ") + e.error_);
596                return false;
597        } catch(const std::exception &e) {
598                LOG_ERROR_CORE_STD(_T("Module (") + plugin + _T(") was not found: ") + utf8::to_unicode(e.what()));
599                return false;
600        } catch(...) {
601                LOG_ERROR_CORE_STD(_T("Module (") + plugin + _T(") was not found..."));
602                return false;
603        }
604        return true;
605}
606bool NSClientT::boot_start_plugins(bool boot) {
607        try {
608                loadPlugins(boot?NSCAPI::normalStart:NSCAPI::dontStart);
609        } catch (...) {
610                LOG_ERROR_CORE_STD(_T("Unknown exception loading plugins"));
611                return false;
612        }
613        LOG_DEBUG_CORE_STD(APPLICATION_NAME _T(" - ") CURRENT_SERVICE_VERSION _T(" Started!"));
614        return true;
615}
616
617void NSClientT::startTrayIcons() {
618//      if (shared_server_.get() == NULL) {
619//              LOG_MESSAGE_STD(_T("No master session so tray icons not started"));
620//              return;
621//      }
622//      remote_processes::PWTS_SESSION_INFO list;
623//      DWORD count;
624//      if (!remote_processes::_WTSEnumerateSessions(WTS_CURRENT_SERVER_HANDLE , 0, 1, &list, &count)) {
625//              LOG_ERROR_STD(_T("Failed to enumerate sessions:" ) + error::lookup::last_error());
626//      } else {
627//              LOG_DEBUG_STD(_T("Found ") + strEx::itos(count) + _T(" sessions"));
628//              for (DWORD i=0;i<count;i++) {
629//                      LOG_DEBUG_STD(_T("Found session: ") + strEx::itos(list[i].SessionId) + _T(" state: ") + strEx::itos(list[i].State));
630//                      if (list[i].State == remote_processes::_WTS_CONNECTSTATE_CLASS::WTSActive) {
631//                              startTrayIcon(list[i].SessionId);
632//                      }
633//              }
634//      }
635}
636void NSClientT::startTrayIcon(DWORD dwSessionId) {
637//      if (shared_server_.get() == NULL) {
638//              LOG_MESSAGE_STD(_T("No master session so tray icons not started"));
639//              return;
640//      }
641//      if (!shared_server_->re_attach_client(dwSessionId)) {
642//              if (!tray_starter::start(dwSessionId)) {
643//                      LOG_ERROR_STD(_T("Failed to start session (") + strEx::itos(dwSessionId) + _T("): " ) + error::lookup::last_error());
644//              }
645//      }
646}
647
648bool NSClientT::stop_unload_plugins_pre() {
649        LOG_DEBUG_CORE(_T("Attempting to stop all plugins"));
650        try {
651                LOG_DEBUG_CORE(_T("Stopping all plugins"));
652                mainClient.unloadPlugins();
653        } catch(NSPluginException e) {
654                LOG_ERROR_CORE_STD(_T("Exception raised when unloading non msg plguins: ") + e.error_ + _T(" in module: ") + e.file_);
655        } catch(...) {
656                LOG_ERROR_CORE_STD(_T("Unknown exception raised when unloading non msg plugins"));
657        }
658        return true;
659}
660bool NSClientT::stop_exit_pre() {
661#ifdef WIN32
662        LOG_DEBUG_CORE(_T("Stopping: COM helper"));
663        try {
664                com_helper_.unInitialize();
665        } catch (com_helper::com_exception e) {
666                LOG_ERROR_CORE_STD(_T("COM exception: ") + e.getMessage());
667        } catch (...) {
668                LOG_ERROR_CORE_STD(_T("Unknown exception uniniating COM..."));
669        }
670#endif
671        /*
672        LOG_DEBUG_STD(_T("Stopping: Socket Helpers"));
673        try {
674                simpleSocket::WSACleanup();
675        } catch (simpleSocket::SocketException e) {
676                LOG_ERROR_STD(_T("Socket exception: ") + e.getMessage());
677        } catch (...) {
678                LOG_ERROR_STD(_T("Unknown exception uniniating socket..."));
679        }
680        */
681        LOG_DEBUG_CORE(_T("Stopping: Settings instance"));
682        settings_manager::destroy_settings();
683//      try {
684//              if (shared_client_.get() != NULL) {
685//                      LOG_DEBUG_STD(_T("Stopping: shared client"));
686//                      shared_client_->set_handler(NULL);
687//                      shared_client_->close_session();
688//              }
689//      } catch(nsclient_session::session_exception &e) {
690//              LOG_ERROR_STD(_T("Exception closing shared client session: ") + e.what());
691//      } catch(...) {
692//              LOG_ERROR_STD(_T("Exception closing shared client session: Unknown exception!"));
693//      }
694        try {
695//              if (shared_server_.get() != NULL) {
696//                      LOG_DEBUG_STD(_T("Stopping: shared server"));
697//                      shared_server_->set_handler(NULL);
698//                      shared_server_->close_session();
699//              }
700        } catch(...) {
701                LOG_ERROR_CORE_STD(_T("UNknown exception raised: When closing shared session"));
702        }
703        return true;
704}
705bool NSClientT::stop_exit_post() {
706        try {
707                nsclient::logging::logger::shutdown();
708                google::protobuf::ShutdownProtobufLibrary();
709        } catch(...) {
710                LOG_ERROR_CORE_STD(_T("UNknown exception raised: When closing shared session"));
711        }
712        return true;
713}
714
715void NSClientT::service_on_session_changed(unsigned long dwSessionId, bool logon, unsigned long dwEventType) {
716//      if (shared_server_.get() == NULL) {
717//              LOG_DEBUG_STD(_T("No shared session: ignoring change event!"));
718//              return;
719//      }
720//      LOG_DEBUG_CORE_STD(_T("Got session change: ") + strEx::itos(dwSessionId));
721//      if (!logon) {
722//              LOG_DEBUG_CORE_STD(_T("Not a logon event: ") + strEx::itos(dwEventType));
723//              return;
724//      }
725//      tray_starter::start(dwSessionId);
726}
727
728//////////////////////////////////////////////////////////////////////////
729// Member functions
730
731
732
733/**
734 * Unload all plug-ins (in reversed order)
735 */
736void NSClientT::unloadPlugins() {
737        nsclient::logging::logger::clear_subscribers();
738        {
739                boost::shared_lock<boost::shared_mutex> readLock(m_mutexRW, boost::get_system_time() + boost::posix_time::milliseconds(5000));
740                if (!readLock.owns_lock()) {
741                        LOG_ERROR_CORE(_T("FATAL ERROR: Could not get read-mutex (004)."));
742                        return;
743                }
744                BOOST_FOREACH(plugin_type &p, plugins_) {
745                        if (!p)
746                                continue;
747                        try {
748                                LOG_DEBUG_CORE_STD(_T("Unloading plugin: ") + p->getModule() + _T("..."));
749                                p->unload_plugin();
750                        } catch(const NSPluginException &e) {
751                                LOG_ERROR_CORE_STD(_T("Exception raised when unloading plugin: ") + e.error_ + _T(" in module: ") + e.file_);
752                        } catch(...) {
753                                LOG_ERROR_CORE_STD(_T("Unknown exception raised when unloading plugin"));
754                        }
755                }
756        }
757        {
758                boost::unique_lock<boost::shared_mutex> writeLock(m_mutexRW, boost::get_system_time() + boost::posix_time::seconds(10));
759                if (!writeLock.owns_lock()) {
760                        LOG_ERROR_CORE(_T("FATAL ERROR: Could not get read-mutex (005)."));
761                        return;
762                }
763                commands_.remove_all();
764                channels_.remove_all();
765                routers_.remove_all();
766                plugins_.clear();
767        }
768}
769
770NSCAPI::errorReturn NSClientT::reload(const std::wstring module) {
771        if (module == _T("settings")) {
772                try {
773                        settings_manager::get_settings()->clear_cache();
774                        return NSCAPI::isSuccess;
775                } catch(const std::exception &e) {
776                        LOG_ERROR_CORE_STD(_T("Exception raised when reloading: ") + utf8::to_unicode(e.what()));
777                } catch(...) {
778                        LOG_ERROR_CORE_STD(_T("Exception raised when reloading: UNKNOWN"));
779                }
780        } else if (module == _T("service")) {
781                try {
782                        stop_unload_plugins_pre();
783                        boot_load_all_plugins();
784                        boot_start_plugins(true);
785                        return NSCAPI::isSuccess;
786                } catch(const std::exception &e) {
787                        LOG_ERROR_CORE_STD(_T("Exception raised when reloading: ") + utf8::to_unicode(e.what()));
788                } catch(...) {
789                        LOG_ERROR_CORE_STD(_T("Exception raised when reloading: UNKNOWN"));
790                }
791        } else {
792                boost::unique_lock<boost::shared_mutex> writeLock(m_mutexRW, boost::get_system_time() + boost::posix_time::seconds(10));
793                if (!writeLock.owns_lock()) {
794                        LOG_ERROR_CORE(_T("FATAL ERROR: Could not get read-mutex (007a)."));
795                        return NSCAPI::hasFailed;
796                }
797
798                BOOST_FOREACH(plugin_type &p, plugins_) {
799                        if (p->get_alias() == module) {
800                                LOG_DEBUG_CORE_STD(_T("Found module: ") + module + _T(", reloading..."));
801                                p->unload_plugin();
802                                p->load_plugin(NSCAPI::normalStart);
803                                return NSCAPI::isSuccess;
804                        }
805                }
806        }
807        return NSCAPI::hasFailed;
808}
809
810void NSClientT::loadPlugins(NSCAPI::moduleLoadMode mode) {
811        {
812                boost::shared_lock<boost::shared_mutex> readLock(m_mutexRW, boost::get_system_time() + boost::posix_time::milliseconds(5000));
813                if (!readLock.owns_lock()) {
814                        LOG_ERROR_CORE(_T("FATAL ERROR: Could not get read-mutex (006)."));
815                        return;
816                }
817                for (pluginList::iterator it=plugins_.begin(); it != plugins_.end();) {
818                        LOG_DEBUG_CORE_STD(_T("Loading plugin: ") + (*it)->get_description());
819                        try {
820                                if (!(*it)->load_plugin(mode)) {
821                                        LOG_ERROR_CORE_STD(_T("Plugin refused to load: ") + (*it)->getModule());
822                                        it = plugins_.erase(it);
823                                } else
824                                        ++it;
825                        } catch (NSPluginException e) {
826                                it = plugins_.erase(it);
827                                LOG_ERROR_CORE_STD(_T("Could not load plugin: ") + e.file_ + _T(": ") + e.error_);
828                        } catch (...) {
829                                it = plugins_.erase(it);
830                                LOG_ERROR_CORE_STD(_T("Could not load plugin: ") + (*it)->getModule());
831                        }
832                }
833        }
834}
835/**
836 * Load and add a plugin to various internal structures
837 * @param plugin The plug-in instance to load. The pointer is managed by the
838 */
839NSClientT::plugin_type NSClientT::addPlugin(boost::filesystem::wpath file, std::wstring alias) {
840        {
841                LOG_DEBUG_CORE_STD(_T("addPlugin(") + file.string() + _T(" as ") + alias + _T(")"));
842                // Check if this is a duplicate plugin (if so return that instance)
843                boost::unique_lock<boost::shared_mutex> writeLock(m_mutexRW, boost::get_system_time() + boost::posix_time::seconds(10));
844                if (!writeLock.owns_lock()) {
845                        LOG_ERROR_CORE(_T("FATAL ERROR: Could not get read-mutex (007a)."));
846                        return plugin_type();
847                }
848
849                BOOST_FOREACH(plugin_type plug, plugins_) {
850                        if (plug->is_duplicate(file, alias)) {
851                                LOG_DEBUG_CORE_STD(_T("Found duplicate plugin returning old ") + to_wstring(plug->get_id()));
852                                return plug;
853                        }
854                }
855
856        }
857
858
859        plugin_type plugin(new NSCPlugin(next_plugin_id_++, file, alias));
860        plugin->load_dll();
861        {
862                boost::unique_lock<boost::shared_mutex> writeLock(m_mutexRW, boost::get_system_time() + boost::posix_time::seconds(10));
863                if (!writeLock.owns_lock()) {
864                        LOG_ERROR_CORE(_T("FATAL ERROR: Could not get read-mutex (007b)."));
865                        return plugin;
866                }
867
868                plugins_.insert(plugins_.end(), plugin);
869                if (plugin->hasCommandHandler())
870                        commands_.add_plugin(plugin);
871                if (plugin->hasNotificationHandler())
872                        channels_.add_plugin(plugin);
873                if (plugin->hasMessageHandler())
874                        nsclient::logging::logger::subscribe_raw(plugin);
875                if (plugin->has_routing_handler())
876                        routers_.add_plugin(plugin);
877                settings_manager::get_core()->register_key(_T("/modules"), plugin->getModule(), settings::settings_core::key_string, plugin->getName(), plugin->getDescription(), _T("0"), false);
878        }
879        return plugin;
880}
881
882
883std::wstring NSClientT::describeCommand(std::wstring command) {
884        return commands_.describe(command);
885}
886std::list<std::wstring> NSClientT::getAllCommandNames() {
887        return commands_.list();
888}
889void NSClientT::registerCommand(unsigned int id, std::wstring cmd, std::wstring desc) {
890        return commands_.register_command(id, cmd, desc);
891}
892
893NSCAPI::nagiosReturn NSClientT::inject(std::wstring command, std::wstring arguments, std::wstring &msg, std::wstring & perf) {
894        /*if (shared_client_.get() != NULL && shared_client_->hasMaster()) {
895                try {
896                        return shared_client_->inject(command, arguments, splitter, escape, msg, perf);
897                } catch (nsclient_session::session_exception &e) {
898                        LOG_ERROR_STD(_T("Failed to inject remote command: ") + e.what());
899                        return NSCAPI::returnCRIT;
900                } catch (...) {
901                        LOG_ERROR_STD(_T("Failed to inject remote command: Unknown exception"));
902                        return NSCAPI::returnCRIT;
903                }
904        } else */{
905
906                std::list<std::wstring> args;
907                strEx::parse_command(arguments, args);
908                std::string request, response;
909                nscapi::functions::create_simple_query_request(command, args, request);
910                NSCAPI::nagiosReturn ret = injectRAW(command.c_str(), request, response);
911                if (response.empty()) {
912                        LOG_ERROR_CORE(_T("No data retutned from command"));
913                        return NSCAPI::returnUNKNOWN;
914                }
915                nscapi::functions::parse_simple_query_response(response, msg, perf);
916                return ret;
917        }
918}
919
920/**
921 * Inject a command into the plug-in stack.
922 *
923 * @param command Command to inject
924 * @param argLen Length of argument buffer
925 * @param **argument Argument buffer
926 * @param *returnMessageBuffer Message buffer
927 * @param returnMessageBufferLen Length of returnMessageBuffer
928 * @param *returnPerfBuffer Performance data buffer
929 * @param returnPerfBufferLen Length of returnPerfBuffer
930 * @return The command status
931 */
932NSCAPI::nagiosReturn NSClientT::injectRAW(const wchar_t* raw_command, std::string &request, std::string &response) {
933        std::wstring cmd = nsclient::commands::make_key(raw_command);
934        LOG_DEBUG_CORE_STD(_T("Injecting: ") + cmd + _T("..."));
935        /*if (shared_client_.get() != NULL && shared_client_->hasMaster()) {
936                try {
937                        std::wstring msg, perf;
938                        int returnCode = shared_client_->inject(command, arrayBuffer::arrayBuffer2string(argument, argLen, _T(" ")), L' ', true, msg, perf);
939                        NSCHelper::wrapReturnString(returnMessageBuffer, returnMessageBufferLen, msg, returnCode);
940                        return NSCHelper::wrapReturnString(returnPerfBuffer, returnPerfBufferLen, perf, returnCode);
941                } catch (nsclient_session::session_exception &e) {
942                        LOG_ERROR_STD(_T("Failed to inject remote command: ") + e.what());
943                        int returnCode = NSCHelper::wrapReturnString(returnMessageBuffer, returnMessageBufferLen, _T("Failed to inject remote command: ") + e.what(), NSCAPI::returnCRIT);
944                        return NSCHelper::wrapReturnString(returnPerfBuffer, returnPerfBufferLen, _T(""), returnCode);
945                } catch (...) {
946                        LOG_ERROR_STD(_T("Failed to inject remote command: Unknown exception"));
947                        int returnCode = NSCHelper::wrapReturnString(returnMessageBuffer, returnMessageBufferLen, _T("Failed to inject remote command:  + e.what()"), NSCAPI::returnCRIT);
948                        return NSCHelper::wrapReturnString(returnPerfBuffer, returnPerfBufferLen, _T(""), returnCode);
949                }
950        } else */{
951                try {
952                        nsclient::commands::plugin_type plugin = commands_.get(cmd);
953                        if (!plugin) {
954                                LOG_ERROR_CORE(_T("No handler for command: ") + cmd + _T(" avalible commands: ") + commands_.to_wstring());
955                                nscapi::functions::create_simple_query_response_unknown(cmd, _T("No handler for command: ") + cmd, response);
956                                return NSCAPI::returnIgnored;
957                        }
958                        NSCAPI::nagiosReturn c = plugin->handleCommand(cmd.c_str(), request, response);
959                        LOG_DEBUG_CORE_STD(_T("Result ") + cmd + _T(": ") + nscapi::plugin_helper::translateReturn(c));
960                        return c;
961                } catch (const nsclient::commands::command_exception &e) {
962                        LOG_ERROR_CORE(_T("Failed to process command: ") + cmd + _T(": ") + utf8::to_unicode(e.what()));
963                        return NSCAPI::returnIgnored;
964                } catch (const std::exception &e) {
965                        LOG_ERROR_CORE(_T("Failed to process command: ") + cmd + _T(": ") + utf8::to_unicode(e.what()));
966                        return NSCAPI::returnIgnored;
967                } catch (...) {
968                        LOG_ERROR_CORE(_T("Error handling command: ") + cmd);
969                        return NSCAPI::returnIgnored;
970                }
971        }
972}
973
974
975int NSClientT::load_and_run(std::wstring module, run_function fun, std::list<std::wstring> &errors) {
976        int ret = -1;
977        bool found = false;
978        {
979                boost::shared_lock<boost::shared_mutex> readLock(m_mutexRW, boost::get_system_time() + boost::posix_time::seconds(5));
980                if (!readLock.owns_lock()) {
981                        LOG_ERROR_CORE(_T("FATAL ERROR: Could not get read-mutex (001)."));
982                        return -1;
983                }
984                BOOST_FOREACH(plugin_type plugin, plugins_) {
985                        if (plugin && (module.empty() || plugin->getModule() == module)) {
986                                LOG_DEBUG_CORE_STD(_T("Found module: ") + plugin->getName() + _T("..."));
987                                try {
988                                        ret = fun(plugin);
989                                        found = true;
990                                } catch (const NSPluginException &e) {
991                                        errors.push_back(_T("Could not execute command: ") + e.error_ + _T(" in ") + e.file_);
992                                        return -1;
993                                }
994                        }
995                }
996        }
997        if (!found && !module.empty()) {
998                try {
999                        boost::filesystem::wpath file = NSCPlugin::get_filename(getBasePath() / boost::filesystem::wpath(_T("modules")), module);
1000                        if (boost::filesystem::is_regular(file)) {
1001                                plugin_type plugin = addPlugin(file, _T(""));
1002                                if (plugin) {
1003                                        LOG_DEBUG_CORE_STD(_T("Loading plugin: ") + plugin->getName() + _T("..."));
1004                                        plugin->load_plugin(NSCAPI::dontStart);
1005                                        ret = fun(plugin);
1006                                } else {
1007                                        errors.push_back(_T("Failed to load: ") + std::wstring(module));
1008                                        return 1;
1009                                }
1010                        } else {
1011                                errors.push_back(_T("Failed to load: ") + std::wstring(module));
1012                                return 1;
1013                        }
1014                } catch (const NSPluginException &e) {
1015                        errors.push_back(_T("Module (") + e.file_ + _T(") was not found: ") + e.error_);
1016                } catch(const std::exception &e) {
1017                        errors.push_back(_T("Module (") + module + _T(") was not found: ") + utf8::cvt<std::wstring>(e.what()));
1018                        return 1;
1019                } catch(...) {
1020                        errors.push_back(_T("Module (") + module + _T(") was not found..."));
1021                        return 1;
1022                }
1023        }
1024        return ret;
1025}
1026
1027int exec_helper(NSClientT::plugin_type plugin, std::wstring command, std::vector<std::wstring> arguments, std::string request, std::list<std::string> *responses) {
1028        std::string response;
1029        if (!plugin || !plugin->has_command_line_exec())
1030                return -1;
1031        int ret = plugin->commandLineExec(command.c_str(), request, response);
1032        if (ret != NSCAPI::returnIgnored && !response.empty())
1033                responses->push_back(response);
1034        return ret;
1035}
1036
1037int NSClientT::simple_exec(std::wstring command, std::vector<std::wstring> arguments, std::list<std::wstring> &resp) {
1038        std::string request;
1039        std::list<std::string> responses;
1040        std::list<std::wstring> errors;
1041        nscapi::functions::create_simple_exec_request(command, arguments, request);
1042        std::wstring module;
1043        std::wstring::size_type pos = command.find(L'.');
1044        if (pos != std::wstring::npos) {
1045                module = command.substr(0, pos);
1046                command = command.substr(pos+1);
1047        }
1048        int ret = load_and_run(module, boost::bind(&exec_helper, _1, command, arguments, request, &responses), errors);
1049
1050        BOOST_FOREACH(std::string &r, responses) {
1051                try {
1052                        ret = nscapi::functions::parse_simple_exec_result(r, resp);
1053                } catch (std::exception &e) {
1054                        resp.push_back(_T("Failed to extract return message: ") + utf8::cvt<std::wstring>(e.what()));
1055                        LOG_ERROR_CORE_STD(resp.back());
1056                        return NSCAPI::returnUNKNOWN;
1057                }
1058        }
1059        BOOST_FOREACH(const std::wstring &e, errors) {
1060                LOG_ERROR_CORE_STD(e);
1061                resp.push_back(e);
1062        }
1063        return ret;
1064}
1065int query_helper(NSClientT::plugin_type plugin, std::wstring command, std::vector<std::wstring> arguments, std::string request, std::list<std::string> *responses) {
1066        return NSCAPI::returnIgnored;
1067//      std::string response;
1068//      if (!plugin->hasCommandHandler())
1069//              return NSCAPI::returnIgnored;
1070//      int ret = plugin->handleCommand(command.c_str(), request, response);
1071//      if (ret != NSCAPI::returnIgnored && !response.empty())
1072//              responses->push_back(response);
1073//      return ret;
1074}
1075
1076int NSClientT::simple_query(std::wstring module, std::wstring command, std::vector<std::wstring> arguments, std::list<std::wstring> &resp) {
1077        std::string request;
1078        std::list<std::string> responses;
1079        std::list<std::wstring> errors;
1080        nscapi::functions::create_simple_query_request(command, arguments, request);
1081        int ret = load_and_run(module, boost::bind(&query_helper, _1, command, arguments, request, &responses), errors);
1082
1083        nsclient::commands::plugin_type plugin = commands_.get(command);
1084        if (!plugin) {
1085                LOG_ERROR_CORE(_T("No handler for command: ") + command + _T(" available commands: ") + commands_.to_wstring());
1086                resp.push_back(_T("No handler for command: ") + command);
1087                return NSCAPI::returnUNKNOWN;
1088        }
1089        std::string response;
1090        ret = plugin->handleCommand(command.c_str(), request, response);
1091        try {
1092                std::wstring msg, perf;
1093                nscapi::functions::parse_simple_query_response(response, msg, perf);
1094                resp.push_back(msg + _T("|") + perf);
1095        } catch (std::exception &e) {
1096                resp.push_back(_T("Failed to extract return message: ") + utf8::cvt<std::wstring>(e.what()));
1097                LOG_ERROR_CORE_STD(resp.back());
1098                return NSCAPI::returnUNKNOWN;
1099        }
1100        BOOST_FOREACH(const std::wstring &e, errors) {
1101                LOG_ERROR_CORE_STD(e);
1102                resp.push_back(e);
1103        }
1104        return ret;
1105}
1106
1107NSCAPI::nagiosReturn NSClientT::exec_command(const wchar_t* raw_target, const wchar_t* raw_command, std::string &request, std::string &response) {
1108        std::wstring target = raw_target;
1109        bool match_any = false;
1110        bool match_all = false;
1111        if (target == _T("any"))
1112                match_any = true;
1113        else if (target == _T("all") || target == _T("*"))
1114                match_all = true;
1115        std::list<std::string> responses;
1116        bool found = false;
1117        {
1118                boost::shared_lock<boost::shared_mutex> readLock(m_mutexRW, boost::get_system_time() + boost::posix_time::seconds(5));
1119                if (!readLock.owns_lock()) {
1120                        LOG_ERROR_CORE(_T("FATAL ERROR: Could not get read-mutex (001)."));
1121                        return -1;
1122                }
1123                BOOST_FOREACH(plugin_type p, plugins_) {
1124                        if (p && p->has_command_line_exec()) {
1125                                try {
1126                                        if (match_all || match_any || p->get_alias() == target) {
1127                                                std::string respbuffer;
1128                                                NSCAPI::nagiosReturn r = p->commandLineExec(raw_command, request, respbuffer);
1129                                                if (r != NSCAPI::returnIgnored && !respbuffer.empty()) {
1130                                                        LOG_DEBUG_CORE_STD(_T("Got response from: ") + p->getName());
1131                                                        found = true;
1132                                                        if (match_any) {
1133                                                                response = respbuffer;
1134                                                                return NSCAPI::returnOK;
1135                                                        }
1136                                                        responses.push_back(respbuffer);
1137                                                }
1138                                        }
1139                                } catch (NSPluginException e) {
1140                                        LOG_ERROR_CORE_STD(_T("Could not execute command: ") + e.error_ + _T(" in ") + e.file_);
1141                                }
1142                        }
1143                }
1144        }
1145
1146        Plugin::ExecuteResponseMessage response_message;
1147        nscapi::functions::create_simple_header(response_message.mutable_header());
1148
1149        BOOST_FOREACH(std::string r, responses) {
1150                Plugin::ExecuteResponseMessage tmp;
1151                tmp.ParseFromString(r);
1152                for (int i=0;i<tmp.payload_size();i++) {
1153                        Plugin::ExecuteResponseMessage::Response *r = response_message.add_payload();
1154                        r->CopyFrom(tmp.payload(i));
1155                }
1156        }
1157        response_message.SerializeToString(&response);
1158        if (found)
1159                return NSCAPI::returnOK;
1160        return NSCAPI::returnIgnored;
1161}
1162
1163
1164NSCAPI::errorReturn NSClientT::reroute(std::wstring &channel, std::string &buffer) {
1165        BOOST_FOREACH(nsclient::plugin_type p, routers_.get(channel)) {
1166                wchar_t *new_channel_buffer;
1167                char *new_buffer;
1168                unsigned int new_buffer_len;
1169                int status = p->route_message(channel.c_str(), buffer.c_str(), buffer.size(), &new_channel_buffer, &new_buffer, &new_buffer_len);
1170                if ((status&NSCAPI::message_modified) == NSCAPI::message_modified) {
1171                        buffer = std::string(new_buffer, new_buffer_len);
1172                        p->deleteBuffer(&new_buffer);
1173                }
1174                if ((status&NSCAPI::message_routed) == NSCAPI::message_routed) {
1175                        channel = new_channel_buffer;
1176                        //p->deleteBuffer(new_channel_buffer);
1177                        return NSCAPI::message_routed;
1178                }
1179                if ((status&NSCAPI::message_ignored) == NSCAPI::message_ignored)
1180                        return NSCAPI::message_ignored;
1181                if ((status&NSCAPI::message_digested) == NSCAPI::message_digested)
1182                        return NSCAPI::message_ignored;
1183        }
1184        return NSCAPI::isfalse;
1185}
1186
1187NSCAPI::errorReturn NSClientT::register_submission_listener(unsigned int plugin_id, const wchar_t* channel) {
1188        channels_.register_listener(plugin_id, channel);
1189        return NSCAPI::isSuccess;
1190}
1191NSCAPI::errorReturn NSClientT::register_routing_listener(unsigned int plugin_id, const wchar_t* channel) {
1192        routers_.register_listener(plugin_id, channel);
1193        return NSCAPI::isSuccess;
1194}
1195
1196NSCAPI::errorReturn NSClientT::send_notification(const wchar_t* channel, std::string &request, std::string &response) {
1197        boost::shared_lock<boost::shared_mutex> readLock(m_mutexRW, boost::get_system_time() + boost::posix_time::milliseconds(5000));
1198        if (!readLock.owns_lock()) {
1199                LOG_ERROR_CORE(_T("FATAL ERROR: Could not get read-mutex (009)."));
1200                return NSCAPI::hasFailed;
1201        }
1202
1203        std::wstring schannel = channel;
1204        try {
1205                int count = 0;
1206                while (reroute(schannel, request)==NSCAPI::message_routed && count++ <= 10) {
1207                        LOG_DEBUG_CORE_STD(_T("Re-routing message to: ") + schannel);
1208                }
1209                if (count >= 10) {
1210                        LOG_ERROR_CORE(_T("More then 10 routes, discarding message..."));
1211                        return NSCAPI::hasFailed;
1212                }
1213        } catch (nsclient::plugins_list_exception &e) {
1214                LOG_ERROR_CORE(_T("Error routing channel: ") + std::wstring(channel) + _T(": ") + to_wstring(e.what()) + _T("Current channels: ") + channels_.to_wstring());
1215                return NSCAPI::hasFailed;
1216        } catch (...) {
1217                LOG_ERROR_CORE(_T("Error routing channel: ") + std::wstring(channel));
1218                return NSCAPI::hasFailed;
1219        }
1220
1221        try {
1222                //LOG_ERROR_CORE_STD(_T("Notifying: ") + strEx::strip_hex(to_wstring(std::string(result,result_len))));
1223                bool found = false;
1224                BOOST_FOREACH(nsclient::plugin_type p, channels_.get(schannel)) {
1225                        p->handleNotification(schannel.c_str(), request, response);
1226                        found = true;
1227                }
1228                if (!found) {
1229                        LOG_ERROR_CORE_STD(_T("No one listens for events from: ") + schannel + _T(" (") + std::wstring(channel) + _T(")"));
1230                        return NSCAPI::hasFailed;
1231                }
1232                return NSCAPI::isSuccess;
1233        } catch (nsclient::plugins_list_exception &e) {
1234                LOG_ERROR_CORE(_T("No handler for channel: ") + std::wstring(channel) + _T(": ") + to_wstring(e.what()));
1235                return NSCAPI::hasFailed;
1236        } catch (...) {
1237                LOG_ERROR_CORE(_T("Error handling channel: ") + std::wstring(channel));
1238                return NSCAPI::hasFailed;
1239        }
1240}
1241
1242void NSClientT::listPlugins() {
1243        boost::shared_lock<boost::shared_mutex> readLock(m_mutexRW, boost::get_system_time() + boost::posix_time::milliseconds(5000));
1244        if (!readLock.owns_lock()) {
1245                LOG_ERROR_CORE(_T("FATAL ERROR: Could not get read-mutex (010)."));
1246                return;
1247        }
1248        for (pluginList::iterator it=plugins_.begin(); it != plugins_.end(); ++it) {
1249                try {
1250                        if ((*it)->isBroken()) {
1251                                std::wcout << (*it)->getModule() << _T(": ") << _T("broken") << std::endl;
1252                        } else {
1253                                std::wcout << (*it)->getModule() << _T(": ") << (*it)->getName() << std::endl;
1254                        }
1255                } catch (NSPluginException e) {
1256                        LOG_ERROR_CORE_STD(_T("Could not load plugin: ") + e.file_ + _T(": ") + e.error_);
1257                }
1258        }
1259
1260}
1261
1262boost::filesystem::wpath NSClientT::getBasePath(void) {
1263        boost::unique_lock<boost::timed_mutex> lock(internalVariables, boost::get_system_time() + boost::posix_time::seconds(5));
1264        if (!lock.owns_lock()) {
1265                LOG_ERROR_CORE(_T("FATAL ERROR: Could not get mutex."));
1266                return _T("FATAL ERROR");
1267        }
1268        if (!basePath.empty())
1269                return basePath;
1270#ifdef WIN32
1271        unsigned int buf_len = 4096;
1272        wchar_t* buffer = new wchar_t[buf_len+1];
1273        GetModuleFileName(NULL, buffer, buf_len);
1274        std::wstring path = buffer;
1275        std::wstring::size_type pos = path.rfind('\\');
1276        basePath = path.substr(0, pos) + _T("\\");
1277        delete [] buffer;
1278#else
1279        basePath = to_wstring(boost::filesystem::initial_path().string());
1280#endif
1281        try {
1282                settings_manager::get_core()->set_base(basePath);
1283        } catch (settings::settings_exception e) {
1284                LOG_ERROR_CORE_STD(_T("Failed to set settings file: ") + e.getMessage());
1285        } catch (...) {
1286                LOG_ERROR_CORE_STD(_T("Failed to set settings file"));
1287        }
1288        return basePath;
1289}
1290
1291#ifdef WIN32
1292typedef DWORD (WINAPI *PFGetTempPath)(__in DWORD nBufferLength, __out  LPTSTR lpBuffer);
1293#endif
1294boost::filesystem::wpath NSClientT::getTempPath() {
1295        boost::unique_lock<boost::timed_mutex> lock(internalVariables, boost::get_system_time() + boost::posix_time::seconds(5));
1296        if (!lock.owns_lock()) {
1297                LOG_ERROR_CORE(_T("FATAL ERROR: Could not get mutex."));
1298                return _T("FATAL ERROR");
1299        }
1300        if (!tempPath.empty())
1301                return tempPath;
1302#ifdef WIN32
1303        unsigned int buf_len = 4096;
1304        HMODULE hKernel = ::LoadLibrary(_TEXT("kernel32"));
1305        if (hKernel) 
1306        {
1307                // Find PSAPI functions
1308                PFGetTempPath FGetTempPath = (PFGetTempPath)::GetProcAddress(hKernel, "GetTempPathW");
1309                if (FGetTempPath) {
1310                        wchar_t* buffer = new wchar_t[buf_len+1];
1311                        if (FGetTempPath(buf_len, buffer)) {
1312                                tempPath = buffer;
1313                        }
1314                        delete [] buffer;
1315                }
1316        }
1317#else
1318        tempPath = _T("/tmp");
1319#endif
1320        return tempPath;
1321}
1322
1323// Service API
1324NSClient* NSClientT::get_global_instance() {
1325        return &mainClient;
1326}
1327void NSClientT::handle_startup(std::wstring service_name) {
1328        LOG_DEBUG_CORE(_T("Starting: ") + service_name);
1329        service_name_ = service_name;
1330        boot_init();
1331        boot_load_all_plugins();
1332        boot_start_plugins(true);
1333        LOG_DEBUG_CORE(_T("Starting: DONE"));
1334/*
1335        DWORD dwSessionId = remote_processes::getActiveSessionId();
1336        if (dwSessionId != 0xFFFFFFFF)
1337                tray_starter::start(dwSessionId);
1338        else
1339                LOG_ERROR_STD(_T("Failed to start tray helper:" ) + error::lookup::last_error());
1340                */
1341}
1342void NSClientT::handle_shutdown(std::wstring service_name) {
1343        stop_unload_plugins_pre();
1344        stop_exit_pre();
1345        stop_exit_post();
1346}
1347
1348NSClientT::service_controller NSClientT::get_service_control() {
1349        return service_controller(service_name_);
1350}
1351
1352void NSClientT::service_controller::stop() {
1353#ifdef WIN32
1354        serviceControll::StopNoWait(get_service_name());
1355#endif
1356}
1357void NSClientT::service_controller::start() {
1358#ifdef WIN32
1359        serviceControll::Start(get_service_name());
1360#endif
1361}
1362bool NSClientT::service_controller::is_started() {
1363#ifdef WIN32
1364        try {
1365                if (serviceControll::isStarted(get_service_name())) {
1366                        return true;
1367                }
1368        } catch (...) {
1369                return false;
1370        }
1371#endif
1372        return false;
1373}
1374
1375
1376#ifdef WIN32
1377#ifndef CSIDL_COMMON_APPDATA
1378#define CSIDL_COMMON_APPDATA 0x0023
1379#endif
1380typedef BOOL (WINAPI *fnSHGetSpecialFolderPath)(HWND hwndOwner, LPTSTR lpszPath, int nFolder, BOOL fCreate);
1381
1382__inline BOOL WINAPI _SHGetSpecialFolderPath(HWND hwndOwner, LPTSTR lpszPath, int nFolder, BOOL fCreate) {
1383        static fnSHGetSpecialFolderPath __SHGetSpecialFolderPath = NULL;
1384        if (!__SHGetSpecialFolderPath) {
1385                HMODULE hDLL = LoadLibrary(_T("shfolder.dll"));
1386                if (hDLL != NULL)
1387                        __SHGetSpecialFolderPath = (fnSHGetSpecialFolderPath)GetProcAddress(hDLL,"SHGetSpecialFolderPathW");
1388        }
1389        if(__SHGetSpecialFolderPath)
1390                return __SHGetSpecialFolderPath(hwndOwner, lpszPath, nFolder, fCreate);
1391        return FALSE;
1392}
1393#endif
1394
1395std::wstring NSClientT::getFolder(std::wstring key) {
1396        if (key == _T("certificate-path")) {
1397                return _T("${shared-path}/security");
1398        }
1399        if (key == _T("module-path")) {
1400                return _T("${shared-path}/modules");
1401        }
1402        if (key == _T("temp")) {
1403                return getTempPath().string();
1404        }
1405        if (key == _T("shared-path") || key == _T("base-path") || key == _T("exe-path")) {
1406                return getBasePath().string();
1407        }
1408#ifdef WIN32
1409        if (key == _T("common-appdata")) {
1410                wchar_t buf[MAX_PATH+1];
1411                if (_SHGetSpecialFolderPath(NULL, buf, CSIDL_COMMON_APPDATA, FALSE)) {
1412                        return std::wstring(buf);
1413                }
1414                return _T("");
1415        }
1416#else
1417        if (key == _T("etc")) {
1418                return _T("/etc");
1419        }
1420#endif
1421        return getBasePath().string();
1422}
1423
1424std::wstring NSClientT::expand_path(std::wstring file) {
1425        std::wstring::size_type pos = file.find('$');
1426        while (pos != std::wstring::npos) {
1427                std::wstring::size_type pstart = file.find('{', pos);
1428                std::wstring::size_type pend = file.find('}', pstart);
1429                std::wstring key = file.substr(pstart+1, pend-2);
1430                //LOG_DEBUG_CORE(_T("Found key: ") + key);
1431
1432                std::wstring tmp = file;
1433                strEx::replace(file, _T("${") + key + _T("}"), getFolder(key));
1434                if (file == tmp)
1435                        pos = file.find_first_of('$', pos);
1436                else
1437                        pos = file.find_first_of('$');
1438        }
1439        return file;
1440}
1441
1442#ifdef _WIN32
1443void NSClientT::handle_session_change(unsigned long dwSessionId, bool logon) {
1444
1445}
1446#endif
Note: See TracBrowser for help on using the repository browser.