source: nscp/service/NSClient++.cpp @ 8013c0c

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