| 1 | /**************************************************************************
|
|---|
| 2 | * Copyright (C) 2004-2007 by Michael Medin <michael@medin.name> *
|
|---|
| 3 | * *
|
|---|
| 4 | * This code is part of NSClient++ - http://trac.nakednuns.org/nscp *
|
|---|
| 5 | * *
|
|---|
| 6 | * This program is free software; you can redistribute it and/or modify *
|
|---|
| 7 | * it under the terms of the GNU General Public License as published by *
|
|---|
| 8 | * the Free Software Foundation; either version 2 of the License, or *
|
|---|
| 9 | * (at your option) any later version. *
|
|---|
| 10 | * *
|
|---|
| 11 | * This program is distributed in the hope that it will be useful, *
|
|---|
| 12 | * but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|---|
| 13 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|---|
| 14 | * GNU General Public License for more details. *
|
|---|
| 15 | * *
|
|---|
| 16 | * You should have received a copy of the GNU General Public License *
|
|---|
| 17 | * along with this program; if not, write to the *
|
|---|
| 18 | * Free Software Foundation, Inc., *
|
|---|
| 19 | * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
|
|---|
| 20 | ***************************************************************************/
|
|---|
| 21 | #include "stdafx.h"
|
|---|
| 22 | #include "CheckExternalScripts.h"
|
|---|
| 23 | #include <time.h>
|
|---|
| 24 | #include <string>
|
|---|
| 25 |
|
|---|
| 26 | #include <strEx.h>
|
|---|
| 27 | #include <file_helpers.hpp>
|
|---|
| 28 |
|
|---|
| 29 | #include <boost/regex.hpp>
|
|---|
| 30 | #include <boost/filesystem.hpp>
|
|---|
| 31 |
|
|---|
| 32 | #include <settings/client/settings_client.hpp>
|
|---|
| 33 | #include <nscapi/functions.hpp>
|
|---|
| 34 | #include <nscapi/nscapi_core_helper.hpp>
|
|---|
| 35 |
|
|---|
| 36 | #include <config.h>
|
|---|
| 37 |
|
|---|
| 38 | namespace sh = nscapi::settings_helper;
|
|---|
| 39 |
|
|---|
| 40 | CheckExternalScripts::CheckExternalScripts() {}
|
|---|
| 41 | CheckExternalScripts::~CheckExternalScripts() {}
|
|---|
| 42 |
|
|---|
| 43 | void CheckExternalScripts::addAllScriptsFrom(std::wstring str_path) {
|
|---|
| 44 | boost::filesystem::wpath path = str_path;
|
|---|
| 45 | if (path.has_relative_path())
|
|---|
| 46 | path = get_core()->getBasePath() / path;
|
|---|
| 47 | file_helpers::patterns::pattern_type split_path = file_helpers::patterns::split_pattern(path);
|
|---|
| 48 | if (!boost::filesystem::is_directory(split_path.first))
|
|---|
| 49 | NSC_LOG_ERROR_STD(_T("Path was not found: ") + split_path.first.string());
|
|---|
| 50 |
|
|---|
| 51 | boost::wregex pattern(split_path.second);
|
|---|
| 52 | boost::filesystem::wdirectory_iterator end_itr; // default construction yields past-the-end
|
|---|
| 53 | for ( boost::filesystem::wdirectory_iterator itr( split_path.first ); itr != end_itr; ++itr ) {
|
|---|
| 54 | if ( !is_directory(itr->status()) ) {
|
|---|
| 55 | std::wstring name = itr->path().leaf();
|
|---|
| 56 | if (regex_match(name, pattern))
|
|---|
| 57 | add_command(name.c_str(), (split_path.first / name).string());
|
|---|
| 58 | }
|
|---|
| 59 | }
|
|---|
| 60 | }
|
|---|
| 61 |
|
|---|
| 62 |
|
|---|
| 63 | /**
|
|---|
| 64 | * Load (initiate) module.
|
|---|
| 65 | * Start the background collector thread and let it run until unloadModule() is called.
|
|---|
| 66 | * @return true
|
|---|
| 67 | */
|
|---|
| 68 | bool CheckExternalScripts::loadModule() {
|
|---|
| 69 | return false;
|
|---|
| 70 | }
|
|---|
| 71 |
|
|---|
| 72 |
|
|---|
| 73 |
|
|---|
| 74 | bool CheckExternalScripts::loadModuleEx(std::wstring alias, NSCAPI::moduleLoadMode mode) {
|
|---|
| 75 | try {
|
|---|
| 76 |
|
|---|
| 77 | sh::settings_registry settings(get_settings_proxy());
|
|---|
| 78 | settings.set_alias(alias, _T("external scripts"));
|
|---|
| 79 |
|
|---|
| 80 | commands_path = settings.alias().get_settings_path(_T("scripts"));
|
|---|
| 81 | aliases_path = settings.alias().get_settings_path(_T("alias"));
|
|---|
| 82 | std::wstring wrappings_path = settings.alias().get_settings_path(_T("wrappings"));
|
|---|
| 83 |
|
|---|
| 84 | settings.alias().add_path_to_settings()
|
|---|
| 85 |
|
|---|
| 86 | (_T("wrappings"), sh::wstring_map_path(&wrappings_)
|
|---|
| 87 | , _T("EXTERNAL SCRIPT WRAPPINGS SECTION"), _T("A list of templates for wrapped scripts"))
|
|---|
| 88 |
|
|---|
| 89 | ;
|
|---|
| 90 |
|
|---|
| 91 | settings.register_all();
|
|---|
| 92 | settings.notify();
|
|---|
| 93 | settings.clear();
|
|---|
| 94 |
|
|---|
| 95 | if (wrappings_.empty()) {
|
|---|
| 96 | NSC_DEBUG_MSG(_T("No wrappings found (adding default: vbs, ps1 and bat)"));
|
|---|
| 97 | wrappings_[_T("vbs")] = _T("cscript.exe //T:30 //NoLogo scripts\\\\lib\\\\wrapper.vbs %SCRIPT% %ARGS%");
|
|---|
| 98 | wrappings_[_T("ps1")] = _T("cmd /c echo scripts\\\\%SCRIPT% %ARGS%; exit($lastexitcode) | powershell.exe -command -");
|
|---|
| 99 | wrappings_[_T("bat")] = _T("scripts\\\\%SCRIPT% %ARGS%");
|
|---|
| 100 | get_core()->settings_register_key(wrappings_path, _T("vbs"), NSCAPI::key_string, _T("VISUAL BASIC WRAPPING"), _T(""), wrappings_[_T("vbs")], false);
|
|---|
| 101 | get_core()->settings_register_key(wrappings_path, _T("ps1"), NSCAPI::key_string, _T("POWERSHELL WRAPPING"), _T(""), wrappings_[_T("ps1")], false);
|
|---|
| 102 | get_core()->settings_register_key(wrappings_path, _T("bat"), NSCAPI::key_string, _T("BATCH FILE WRAPPING"), _T(""), wrappings_[_T("bat")], false);
|
|---|
| 103 | }
|
|---|
| 104 |
|
|---|
| 105 | settings.alias().add_path_to_settings()
|
|---|
| 106 | (_T("EXTERNAL SCRIPT SECTION"), _T("Section for external scripts configuration options (CheckExternalScripts)."))
|
|---|
| 107 |
|
|---|
| 108 | (_T("scripts"), sh::fun_values_path(boost::bind(&CheckExternalScripts::add_command, this, _1, _2)),
|
|---|
| 109 | _T("EXTERNAL SCRIPT SCRIPT SECTION"), _T("A list of scripts available to run from the CheckExternalScripts module. Syntax is: <command>=<script> <arguments>"))
|
|---|
| 110 |
|
|---|
| 111 | (_T("alias"), sh::fun_values_path(boost::bind(&CheckExternalScripts::add_alias, this, _1, _2)),
|
|---|
| 112 | _T("EXTERNAL SCRIPT ALIAS SECTION"), _T("A list of aliases available. An alias is an internal command that has been \"wrapped\" (to add arguments). Be careful so you don't create loops (ie check_loop=check_a, check_a=check_loop)"))
|
|---|
| 113 |
|
|---|
| 114 | (_T("wrapped scripts"), sh::fun_values_path(boost::bind(&CheckExternalScripts::add_wrapping, this, _1, _2)),
|
|---|
| 115 | _T("EXTERNAL SCRIPT WRAPPED SCRIPTS SECTION"), _T("A list of wrappped scripts (ie. using the template mechanism)"))
|
|---|
| 116 |
|
|---|
| 117 | ;
|
|---|
| 118 |
|
|---|
| 119 | settings.alias().add_key_to_settings()
|
|---|
| 120 | (_T("timeout"), sh::uint_key(&timeout, 60),
|
|---|
| 121 | _T("COMMAND TIMEOUT"), _T("The maximum time in seconds that a command can execute. (if more then this execution will be aborted). NOTICE this only affects external commands not internal ones."))
|
|---|
| 122 |
|
|---|
| 123 | (_T("allow arguments"), sh::bool_key(&allowArgs_, false),
|
|---|
| 124 | _T("COMMAND ARGUMENT PROCESSING"), _T("This option determines whether or not the we will allow clients to specify arguments to commands that are executed."))
|
|---|
| 125 |
|
|---|
| 126 | (_T("allow nasty characters"), sh::bool_key(&allowNasty_, false),
|
|---|
| 127 | _T("COMMAND ALLOW NASTY META CHARS"), _T("This option determines whether or not the we will allow clients to specify nasty (as in |`&><'\"\\[]{}) characters in arguments."))
|
|---|
| 128 |
|
|---|
| 129 | (_T("script path"), sh::wstring_key(&scriptDirectory_),
|
|---|
| 130 | _T("SCRIPT DIRECTORY"), _T("Load all scripts in a directory and use them as commands. Probably dangerous but useful if you have loads of scripts :)"))
|
|---|
| 131 | ;
|
|---|
| 132 |
|
|---|
| 133 | settings.register_all();
|
|---|
| 134 | settings.notify();
|
|---|
| 135 |
|
|---|
| 136 |
|
|---|
| 137 | if (!scriptDirectory_.empty()) {
|
|---|
| 138 | addAllScriptsFrom(scriptDirectory_);
|
|---|
| 139 | }
|
|---|
| 140 | root_ = get_core()->getBasePath();
|
|---|
| 141 |
|
|---|
| 142 | BOOST_FOREACH(const commands::command_handler::object_list_type::value_type &o, commands_.object_list) {
|
|---|
| 143 | NSC_DEBUG_MSG(_T("Registring command: ") + o.second.to_wstring());
|
|---|
| 144 | register_command(o.second.alias, _T("Alias for: ") + o.second.alias);
|
|---|
| 145 | }
|
|---|
| 146 | BOOST_FOREACH(const commands::command_handler::object_list_type::value_type &o, aliases_.object_list) {
|
|---|
| 147 | NSC_DEBUG_MSG(_T("Registring alias: ") + o.second.to_wstring());
|
|---|
| 148 | register_command(o.second.alias, _T("Alias for: ") + o.second.alias);
|
|---|
| 149 | }
|
|---|
| 150 |
|
|---|
| 151 |
|
|---|
| 152 | // } catch (nrpe::server::nrpe_exception &e) {
|
|---|
| 153 | // NSC_LOG_ERROR_STD(_T("Exception caught: ") + e.what());
|
|---|
| 154 | // return false;
|
|---|
| 155 | } catch (...) {
|
|---|
| 156 | NSC_LOG_ERROR_STD(_T("Exception caught: <UNKNOWN EXCEPTION>"));
|
|---|
| 157 | return false;
|
|---|
| 158 | }
|
|---|
| 159 | return true;
|
|---|
| 160 | }
|
|---|
| 161 | bool CheckExternalScripts::unloadModule() {
|
|---|
| 162 | return true;
|
|---|
| 163 | }
|
|---|
| 164 |
|
|---|
| 165 | void CheckExternalScripts::add_command(std::wstring key, std::wstring arg) {
|
|---|
| 166 | try {
|
|---|
| 167 | commands_.add(get_settings_proxy(), commands_path, key, arg, key == _T("default"));
|
|---|
| 168 | } catch (const std::exception &e) {
|
|---|
| 169 | NSC_LOG_ERROR_STD(_T("Failed to add command: ") + key + _T(", ") + utf8::to_unicode(e.what()));
|
|---|
| 170 | } catch (...) {
|
|---|
| 171 | NSC_LOG_ERROR_STD(_T("Failed to add command: ") + key);
|
|---|
| 172 | }
|
|---|
| 173 | }
|
|---|
| 174 | void CheckExternalScripts::add_alias(std::wstring key, std::wstring arg) {
|
|---|
| 175 | try {
|
|---|
| 176 | aliases_.add(get_settings_proxy(), aliases_path, key, arg, key == _T("default"));
|
|---|
| 177 | } catch (const std::exception &e) {
|
|---|
| 178 | NSC_LOG_ERROR_STD(_T("Failed to add alias: ") + key + _T(", ") + utf8::to_unicode(e.what()));
|
|---|
| 179 | } catch (...) {
|
|---|
| 180 | NSC_LOG_ERROR_STD(_T("Failed to add alias: ") + key);
|
|---|
| 181 | }
|
|---|
| 182 | }
|
|---|
| 183 |
|
|---|
| 184 |
|
|---|
| 185 | bool CheckExternalScripts::hasCommandHandler() {
|
|---|
| 186 | return true;
|
|---|
| 187 | }
|
|---|
| 188 | bool CheckExternalScripts::hasMessageHandler() {
|
|---|
| 189 | return false;
|
|---|
| 190 | }
|
|---|
| 191 |
|
|---|
| 192 | NSCAPI::nagiosReturn CheckExternalScripts::handleRAWCommand(const wchar_t* char_command, const std::string &request, std::string &response) {
|
|---|
| 193 | nscapi::functions::decoded_simple_command_data data = nscapi::functions::parse_simple_query_request(char_command, request);
|
|---|
| 194 |
|
|---|
| 195 | commands::optional_command_object cmd = commands_.find_object(data.command);
|
|---|
| 196 | bool isAlias = !cmd;
|
|---|
| 197 | if (!cmd)
|
|---|
| 198 | cmd = aliases_.find_object(data.command);
|
|---|
| 199 | if (!cmd)
|
|---|
| 200 | return NSCAPI::returnIgnored;
|
|---|
| 201 |
|
|---|
| 202 | const commands::command_object cd = *cmd;
|
|---|
| 203 | std::list<std::wstring> args = cd.arguments;
|
|---|
| 204 | bool first = true;
|
|---|
| 205 | if (isAlias || allowArgs_) {
|
|---|
| 206 | BOOST_FOREACH(std::wstring &arg, args) {
|
|---|
| 207 | int i=1;
|
|---|
| 208 | BOOST_FOREACH(std::wstring str, data.args) {
|
|---|
| 209 | if (first && !isAlias && !allowNasty_) {
|
|---|
| 210 | if (str.find_first_of(NASTY_METACHARS_W) != std::wstring::npos) {
|
|---|
| 211 | return nscapi::functions::create_simple_query_response_unknown(data.command, _T("Request contained illegal characters!"), _T(""), response);
|
|---|
| 212 | }
|
|---|
| 213 | }
|
|---|
| 214 | strEx::replace(arg, _T("$ARG") + strEx::itos(i++) + _T("$"), str);
|
|---|
| 215 | }
|
|---|
| 216 | }
|
|---|
| 217 | } else if (!allowArgs_ && data.args.size() > 0) {
|
|---|
| 218 | NSC_LOG_ERROR_STD(_T("Arguments not allowed in CheckExternalScripts set /settings/external scripts/allow arguments=true"))
|
|---|
| 219 | }
|
|---|
| 220 |
|
|---|
| 221 |
|
|---|
| 222 | std::wstring xargs;
|
|---|
| 223 | BOOST_FOREACH(std::wstring s, args) {
|
|---|
| 224 | if (!xargs.empty())
|
|---|
| 225 | xargs += _T(" ");
|
|---|
| 226 | xargs += s;
|
|---|
| 227 | }
|
|---|
| 228 |
|
|---|
| 229 | NSC_LOG_MESSAGE(_T("Arguments: ") + xargs);
|
|---|
| 230 |
|
|---|
| 231 |
|
|---|
| 232 | if (isAlias) {
|
|---|
| 233 | std::wstring message;
|
|---|
| 234 | try {
|
|---|
| 235 | return nscapi::core_helper::simple_query(cd.command, args, response);
|
|---|
| 236 | } catch (boost::escaped_list_error &e) {
|
|---|
| 237 | NSC_LOG_MESSAGE(_T("Failed to parse alias expression: ") + strEx::string_to_wstring(e.what()));
|
|---|
| 238 | NSC_LOG_MESSAGE(_T("We will now try parsing the old syntax instead..."));
|
|---|
| 239 | return nscapi::core_helper::simple_query(cd.command, args, response);
|
|---|
| 240 | }
|
|---|
| 241 | } else {
|
|---|
| 242 | std::wstring message, perf;
|
|---|
| 243 | process::exec_arguments args(root_, cd.command + _T(" ") + xargs, timeout);
|
|---|
| 244 | if (!cd.user.empty()) {
|
|---|
| 245 | args.user = cd.user;
|
|---|
| 246 | args.domain = cd.domain;
|
|---|
| 247 | args.password = cd.password;
|
|---|
| 248 | }
|
|---|
| 249 | int result = process::executeProcess(args, message, perf);
|
|---|
| 250 | if (!nscapi::plugin_helper::isNagiosReturnCode(result)) {
|
|---|
| 251 | nscapi::functions::create_simple_query_response_unknown(data.command, _T("The command (") + args.command + _T(") returned an invalid return code: ") + strEx::itos(result), _T(""), response);
|
|---|
| 252 | return NSCAPI::returnUNKNOWN;
|
|---|
| 253 | }
|
|---|
| 254 | nscapi::functions::create_simple_query_response(data.command, nscapi::plugin_helper::int2nagios(result), message, perf, response);
|
|---|
| 255 | return result;
|
|---|
| 256 | }
|
|---|
| 257 | }
|
|---|
| 258 | NSC_WRAP_DLL();
|
|---|
| 259 | NSC_WRAPPERS_MAIN_DEF(CheckExternalScripts);
|
|---|
| 260 | NSC_WRAPPERS_IGNORE_MSG_DEF();
|
|---|
| 261 | NSC_WRAPPERS_HANDLE_CMD_DEF();
|
|---|
| 262 |
|
|---|