source: nscp/modules/NRPEClient/NRPEClient.cpp @ cad08fb

0.4.00.4.10.4.2
Last change on this file since cad08fb was cad08fb, checked in by Michael Medin <michael@…>, 3 years ago

Major update with a new plugin glue that works better with *nix.
Everything should be the same but look tidier

  • Property mode set to 100644
File size: 10.9 KB
Line 
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 "NRPEClient.h"
23#include <strEx.h>
24#include <time.h>
25#include <config.h>
26#include <msvc_wrappers.h>
27//#include <execute_process.hpp>
28#include <strEx.h>
29#include <boost/filesystem.hpp>
30#include <strEx.h>
31#include <nrpe/nrpe_socket.hpp>
32
33
34NRPEClient gNRPEClient;
35
36NRPEClient::NRPEClient() : buffer_length_(0) {
37}
38
39NRPEClient::~NRPEClient() {
40}
41
42bool NRPEClient::loadModule(NSCAPI::moduleLoadMode mode) {
43        std::list<std::wstring> commands;
44        buffer_length_ = SETTINGS_GET_INT(nrpe::PAYLOAD_LENGTH);
45        try {
46                SETTINGS_REG_PATH(nrpe::CH_SECTION);
47                commands = GET_CORE()->getSettingsSection(setting_keys::nrpe::CH_SECTION_PATH);
48        } catch (nscapi::nscapi_exception &e) {
49                NSC_LOG_ERROR_STD(_T("Failed to register command: ") + e.msg_);
50        } catch (...) {
51                NSC_LOG_ERROR_STD(_T("Failed to register command."));
52        }
53
54        boost::filesystem::wpath p = GET_CORE()->getBasePath() + std::wstring(_T("security/nrpe_dh_512.pem"));
55        cert_ = p.string();
56        if (boost::filesystem::is_regular(p)) {
57                NSC_DEBUG_MSG_STD(_T("Using certificate: ") + cert_);
58        } else {
59                NSC_LOG_ERROR_STD(_T("Certificate not found: ") + cert_);
60        }
61
62
63        for (std::list<std::wstring>::const_iterator it = commands.begin(); it != commands.end(); ++it) {
64                NSC_DEBUG_MSG_STD(*it);
65                std::wstring s = GET_CORE()->getSettingsString(setting_keys::nrpe::CH_SECTION_PATH, (*it), _T(""));
66                if (s.empty()) {
67                        NSC_LOG_ERROR_STD(_T("Invalid NRPE-client entry: ") + (*it));
68                } else {
69                        addCommand((*it).c_str(), s);
70                }
71        }
72        return true;
73}
74
75void NRPEClient::add_options(po::options_description &desc, nrpe_connection_data &command_data) {
76        desc.add_options()
77                ("help,h", "Show this help message.")
78                ("host,H", po::wvalue<std::wstring>(&command_data.host), "The address of the host running the NRPE daemon")
79                ("port,p", po::value<int>(&command_data.port), "The port on which the daemon is running (default=5666)")
80                ("command,c", po::wvalue<std::wstring>(&command_data.command), "The name of the command that the remote daemon should run")
81                ("timeout,t", po::value<int>(&command_data.timeout), "Number of seconds before connection times out (default=10)")
82                ("buffer-length,l", po::value<unsigned int>(&command_data.buffer_length), std::string("Length of payload (has to be same as on the server (default=" + to_string(buffer_length_) + ")").c_str())
83                ("no-ssl,n", po::value<bool>(&command_data.no_ssl)->zero_tokens()->default_value(false), "Do not initial an ssl handshake with the server, talk in plaintext.")
84                ("arguments,a", po::wvalue<std::vector<std::wstring> >(&command_data.argument_vector), "list of arguments")
85                ;
86}
87
88
89void NRPEClient::addCommand(strEx::blindstr key, std::wstring args) {
90#ifndef USE_BOOST
91        NSC_LOG_ERROR_STD(_T("Could not parse: ") + key.c_str() + _T(" boost not avalible!"));
92#else
93        try {
94
95                NRPEClient::nrpe_connection_data command_data;
96                boost::program_options::variables_map vm;
97
98                po::options_description desc("Allowed options");
99                buffer_length_ = SETTINGS_GET_INT(nrpe::PAYLOAD_LENGTH);
100                add_options(desc, command_data);
101
102                po::positional_options_description p;
103                p.add("arguments", -1);
104
105                std::vector<std::wstring> list;
106                //explicit escaped_list_separator(Char e = '\\', Char c = ',',Char q = '\"')
107                boost::escaped_list_separator<wchar_t> sep(L'\\', L' ', L'\"');
108                typedef boost::tokenizer<boost::escaped_list_separator<wchar_t>,std::wstring::const_iterator, std::wstring > tokenizer_t;
109                tokenizer_t tok(args, sep);
110                for(tokenizer_t::iterator beg=tok.begin(); beg!=tok.end();++beg){
111                        list.push_back(*beg);
112                }
113
114                po::wparsed_options parsed = po::basic_command_line_parser<wchar_t>(list).options(desc).positional(p).run();
115                po::store(parsed, vm);
116                po::notify(vm);
117                command_data.parse_arguments();
118
119                NSC_DEBUG_MSG_STD(_T("Added NRPE Client: ") + key.c_str() + _T(" = ") + command_data.toString());
120                commands[key] = command_data;
121
122                NSCModuleHelper::registerCommand(key.c_str(), command_data.toString());
123
124        } catch (boost::program_options::validation_error &e) {
125                NSC_LOG_ERROR_STD(_T("Could not parse: ") + key.c_str() + strEx::string_to_wstring(e.what()));
126        } catch (...) {
127                NSC_LOG_ERROR_STD(_T("Could not parse: ") + key.c_str());
128        }
129#endif
130}
131
132bool NRPEClient::unloadModule() {
133        return true;
134}
135
136bool NRPEClient::hasCommandHandler() {
137        return true;
138}
139bool NRPEClient::hasMessageHandler() {
140        return false;
141}
142NSCAPI::nagiosReturn NRPEClient::handleCommand(const std::wstring command, std::list<std::wstring> arguments, std::wstring &message, std::wstring &perf)
143{
144        command_list::const_iterator cit = commands.find(strEx::blindstr(command.c_str()));
145        if (cit == commands.end())
146                return NSCAPI::returnIgnored;
147
148        std::wstring args = (*cit).second.arguments;
149        if (SETTINGS_GET_BOOL(nrpe::ALLOW_ARGS) == 1) {
150                int i=1;
151                BOOST_FOREACH(std::wstring arg, arguments)
152                {
153                        if (SETTINGS_GET_INT(nrpe::ALLOW_NASTY) == 0) {
154                                if (arg.find_first_of(NASTY_METACHARS) != std::wstring::npos) {
155                                        NSC_LOG_ERROR(_T("Request string contained illegal metachars!"));
156                                        return NSCAPI::returnIgnored;
157                                }
158                        }
159                        strEx::replace(args, _T("$ARG") + strEx::itos(i++) + _T("$"), arg);
160                }
161        }
162
163        NSC_DEBUG_MSG_STD(_T("Rewrote command arguments: ") + args);
164        nrpe_result_data r = execute_nrpe_command((*cit).second, args);
165        message = r.text;
166        return r.result;
167}
168
169int NRPEClient::commandLineExec(const unsigned int argLen, TCHAR** args) {
170        try {
171
172                NRPEClient::nrpe_connection_data command_data;
173                boost::program_options::variables_map vm;
174
175                po::options_description desc("Allowed options");
176                buffer_length_ = SETTINGS_GET_INT(nrpe::PAYLOAD_LENGTH);
177                add_options(desc, command_data);
178
179                po::positional_options_description p;
180                p.add("arguments", -1);
181                po::wparsed_options parsed = basic_command_line_parser_ex<wchar_t>(argLen, args).options(desc).positional(p).run();
182                po::store(parsed, vm);
183                po::notify(vm);
184                command_data.parse_arguments();
185
186                if (vm.count("help")) {
187                        std::cout << desc << "\n";
188                        return 1;
189                }
190                nrpe_result_data result = execute_nrpe_command(command_data, command_data.arguments);
191                std::wcout << result.text << std::endl;
192                return result.result;
193        } catch (boost::program_options::validation_error &e) {
194                std::cout << e.what() << std::endl;
195        } catch (...) {
196                std::cout << "Unknown exception parsing command line" << std::endl;
197        }
198        return NSCAPI::returnUNKNOWN;
199}
200NRPEClient::nrpe_result_data NRPEClient::execute_nrpe_command(nrpe_connection_data con, std::wstring arguments) {
201        try {
202                nrpe::packet packet;
203                if (!con.no_ssl) {
204#ifdef USE_SSL
205                        packet = send_ssl(con.host, con.port, con.timeout, nrpe::packet::make_request(con.get_cli(arguments), con.buffer_length));
206#else
207                        return nrpe_result_data(NSCAPI::returnUNKNOWN, _T("SSL support not available (compiled without USE_SSL)!"));
208#endif
209                } else
210                        packet = send_nossl(con.host, con.port, con.timeout, nrpe::packet::make_request(con.get_cli(arguments), con.buffer_length));
211                return nrpe_result_data(packet.getResult(), packet.getPayload());
212        } catch (nrpe::nrpe_packet_exception &e) {
213                return nrpe_result_data(NSCAPI::returnUNKNOWN, _T("NRPE Packet errro: ") + e.getMessage());
214        } catch (std::runtime_error &e) {
215                return nrpe_result_data(NSCAPI::returnUNKNOWN, _T("Socket error: ") + boost::lexical_cast<std::wstring>(e.what()));
216        } catch (...) {
217                return nrpe_result_data(NSCAPI::returnUNKNOWN, _T("Unknown error -- REPORT THIS!"));
218        }
219}
220
221
222#ifdef USE_SSL
223nrpe::packet NRPEClient::send_ssl(std::wstring host, int port, int timeout, nrpe::packet packet) {
224        boost::asio::io_service io_service;
225        boost::asio::ssl::context ctx(io_service, boost::asio::ssl::context::sslv23);
226        SSL_CTX_set_cipher_list(ctx.impl(), "ADH");
227        ctx.use_tmp_dh_file(to_string(cert_));
228        ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
229        nrpe::ssl_socket socket(io_service, ctx, host, port);
230        socket.send(packet, boost::posix_time::seconds(timeout));
231        return socket.recv(packet, boost::posix_time::seconds(timeout));
232}
233#endif
234
235nrpe::packet NRPEClient::send_nossl(std::wstring host, int port, int timeout, nrpe::packet packet) {
236        boost::asio::io_service io_service;
237        nrpe::socket socket(io_service, host, port);
238        socket.send(packet, boost::posix_time::seconds(timeout));
239        return socket.recv(packet, boost::posix_time::seconds(timeout));
240}
241
242/*
243NRPEPacket NRPEClient::send_nossl(std::wstring host, int port, int timeout, NRPEPacket packet)
244{
245        unsigned char dh512_p[] = {
246                0xCF, 0xFF, 0x65, 0xC2, 0xC8, 0xB4, 0xD2, 0x68, 0x8C, 0xC1, 0x80, 0xB1,
247                0x7B, 0xD6, 0xE8, 0xB3, 0x62, 0x59, 0x62, 0xED, 0xA7, 0x45, 0x6A, 0xF8,
248                0xE9, 0xD8, 0xBE, 0x3F, 0x38, 0x42, 0x5F, 0xB2, 0xA5, 0x36, 0x03, 0xD3,
249                0x06, 0x27, 0x81, 0xC8, 0x9B, 0x88, 0x50, 0x3B, 0x82, 0x3D, 0x31, 0x45,
250                0x2C, 0xB4, 0xC5, 0xA5, 0xBE, 0x6A, 0xE3, 0x2E, 0xA6, 0x86, 0xFD, 0x6A,
251                0x7E, 0x1E, 0x6A, 0x73,
252        };
253        unsigned char dh512_g[] = { 0x02, };
254
255        DH *dh_2 = DH_new();
256        dh_2->p = BN_bin2bn(dh512_p, sizeof(dh512_p), NULL);
257        dh_2->g = BN_bin2bn(dh512_g, sizeof(dh512_g), NULL);
258
259        FILE *outfile = fopen("d:\\nrpe_512.pem", "w");
260        PEM_write_DHparams(outfile, dh_2);
261        PEM_write_DHparams(stdout, dh_2);
262        fclose(outfile);
263
264        nrpe_socket socket(host, port);
265        socket.send(packet, boost::posix_time::seconds(timeout));
266        return socket.recv(packet, boost::posix_time::seconds(timeout));
267}
268*/
269
270
271
272
273
274NSC_WRAP_DLL();
275NSC_WRAPPERS_MAIN_DEF(gNRPEClient);
276NSC_WRAPPERS_IGNORE_MSG_DEF();
277NSC_WRAPPERS_HANDLE_CMD_DEF(gNRPEClient);
278NSC_WRAPPERS_CLI_DEF(gNRPEClient);
279
Note: See TracBrowser for help on using the repository browser.