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

0.4.00.4.10.4.2
Last change on this file since e396b2f was e396b2f, checked in by Michael Medin <michael@…>, 16 months ago
  • Refactored the targets concept internally to be simpler to use (less code)
  • Fixed issue with reloading plugins
  • Fixed target handling in NRPE Client, will add NSCA client tomorrow...
  • Property mode set to 100644
File size: 15.5 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
24#include <time.h>
25#include <strEx.h>
26
27#include <strEx.h>
28#include <nrpe/client/socket.hpp>
29
30#include <settings/client/settings_client.hpp>
31
32namespace sh = nscapi::settings_helper;
33
34/**
35 * Default c-tor
36 * @return
37 */
38NRPEClient::NRPEClient() {}
39
40/**
41 * Default d-tor
42 * @return
43 */
44NRPEClient::~NRPEClient() {}
45
46/**
47 * Load (initiate) module.
48 * Start the background collector thread and let it run until unloadModule() is called.
49 * @return true
50 */
51bool NRPEClient::loadModule() {
52        return false;
53}
54
55bool NRPEClient::loadModuleEx(std::wstring alias, NSCAPI::moduleLoadMode mode) {
56
57        std::wstring certificate;
58        unsigned int timeout = 30, buffer_length = 1024;
59        bool use_ssl = true;
60        try {
61
62                sh::settings_registry settings(get_settings_proxy());
63                settings.set_alias(_T("NRPE"), alias, _T("client"));
64
65                target_path = settings.alias().get_settings_path(_T("targets"));
66
67                settings.alias().add_path_to_settings()
68                        (_T("NRPE CLIENT SECTION"), _T("Section for NRPE active/passive check module."))
69
70                        (_T("handlers"), sh::fun_values_path(boost::bind(&NRPEClient::add_command, this, _1, _2)),
71                        _T("CLIENT HANDLER SECTION"), _T(""))
72
73                        (_T("targets"), sh::fun_values_path(boost::bind(&NRPEClient::add_target, this, _1, _2)),
74                        _T("REMOTE TARGET DEFINITIONS"), _T(""))
75                        ;
76
77                settings.alias().add_key_to_settings()
78                        (_T("channel"), sh::wstring_key(&channel_, _T("NRPE")),
79                        _T("CHANNEL"), _T("The channel to listen to."))
80
81                        ;
82
83                settings.register_all();
84                settings.notify();
85
86                targets.add_missing(get_settings_proxy(), target_path, _T("default"), _T(""), true);
87
88
89                get_core()->registerSubmissionListener(get_id(), channel_);
90                register_command(_T("nrpe_query"), _T("Check remote NRPE host"));
91                register_command(_T("nrpe_submit"), _T("Submit (via query) remote NRPE host"));
92                register_command(_T("nrpe_forward"), _T("Forward query to remote NRPE host"));
93                register_command(_T("nrpe_exec"), _T("Execute (via query) remote NRPE host"));
94                register_command(_T("nrpe_help"), _T("Help on using NRPE Client"));
95        } catch (nscapi::nscapi_exception &e) {
96                NSC_LOG_ERROR_STD(_T("NSClient API exception: ") + utf8::to_unicode(e.what()));
97                return false;
98        } catch (std::exception &e) {
99                NSC_LOG_ERROR_STD(_T("Exception caught: ") + utf8::to_unicode(e.what()));
100                return false;
101        } catch (...) {
102                NSC_LOG_ERROR_STD(_T("Exception caught: <UNKNOWN EXCEPTION>"));
103                return false;
104        }
105        return true;
106}
107std::string get_command(std::string alias, std::string command = "") {
108        if (!alias.empty())
109                return alias;
110        if (!command.empty())
111                return command;
112        return "_NRPE_CHECK";
113}
114
115//////////////////////////////////////////////////////////////////////////
116// Settings helpers
117//
118
119void NRPEClient::add_target(std::wstring key, std::wstring arg) {
120        try {
121                nscapi::targets::target_object t = targets.add(get_settings_proxy(), target_path , key, arg);
122        } catch (const std::exception &e) {
123                NSC_LOG_ERROR_STD(_T("Failed to add target: ") + key + _T(", ") + utf8::to_unicode(e.what()));
124        } catch (...) {
125                NSC_LOG_ERROR_STD(_T("Failed to add target: ") + key);
126        }
127}
128
129void NRPEClient::add_command(std::wstring name, std::wstring args) {
130        try {
131                std::wstring key = commands.add_command(name, args);
132                if (!key.empty())
133                        register_command(key.c_str(), _T("NRPE relay for: ") + name);
134        } catch (boost::program_options::validation_error &e) {
135                NSC_LOG_ERROR_STD(_T("Could not add command ") + name + _T(": ") + utf8::to_unicode(e.what()));
136        } catch (...) {
137                NSC_LOG_ERROR_STD(_T("Could not add command ") + name);
138        }
139}
140
141/**
142 * Unload (terminate) module.
143 * Attempt to stop the background processing thread.
144 * @return true if successfully, false if not (if not things might be bad)
145 */
146bool NRPEClient::unloadModule() {
147        return true;
148}
149
150NSCAPI::nagiosReturn NRPEClient::handleRAWCommand(const wchar_t* char_command, const std::string &request, std::string &result) {
151        Plugin::QueryRequestMessage message;
152        message.ParseFromString(request);
153        if (message.payload_size() != 1) {
154                return nscapi::functions::create_simple_query_response_unknown(char_command, _T("Multiple payloads currently not supported"), result);
155        }
156        std::string recipient = message.header().recipient_id();
157        nscapi::functions::decoded_simple_command_data data = nscapi::functions::parse_simple_query_request(message.payload(0));
158        std::wstring cmd = client::command_line_parser::parse_command(char_command, _T("nrpe"));
159        client::configuration config;
160        config.data->recipient.id = recipient;
161        setup(config);
162        if (client::command_line_parser::is_command(cmd))
163                return client::command_line_parser::do_execute_command_as_query(config, cmd, data.args, request, result);
164        return commands.exec_simple(config, data.target, cmd, data.args, result);
165}
166
167NSCAPI::nagiosReturn NRPEClient::commandRAWLineExec(const wchar_t* char_command, const std::string &request, std::string &result) {
168        nscapi::functions::decoded_simple_command_data data = nscapi::functions::parse_simple_exec_request(char_command, request);
169        std::wstring cmd = client::command_line_parser::parse_command(char_command, _T("syslog"));
170        if (!client::command_line_parser::is_command(cmd))
171                return NSCAPI::returnIgnored;
172        client::configuration config;
173        setup(config);
174        return client::command_line_parser::do_execute_command_as_exec(config, cmd, data.args, result);
175}
176
177NSCAPI::nagiosReturn NRPEClient::handleRAWNotification(const wchar_t* channel, std::string request, std::string &result) {
178        client::configuration config;
179        setup(config);
180        return client::command_line_parser::do_relay_submit(config, request, result);
181}
182
183//////////////////////////////////////////////////////////////////////////
184// Parser setup/Helpers
185//
186
187void NRPEClient::add_local_options(po::options_description &desc, client::configuration::data_type data) {
188        desc.add_options()
189                ("certificate,c", po::value<std::string>()->notifier(boost::bind(&nscapi::functions::destination_container::set_string_data, &data->recipient, "certificate", _1)),
190                        "Length of payload (has to be same as on the server)")
191
192                ("buffer-length,l", po::value<unsigned int>()->notifier(boost::bind(&nscapi::functions::destination_container::set_int_data, &data->recipient, "payload length", _1)),
193                        "Length of payload (has to be same as on the server)")
194
195                ("no-ssl,n", po::value<bool>()->zero_tokens()->default_value(false)->notifier(boost::bind(&nscapi::functions::destination_container::set_bool_data, &data->recipient, "no ssl", _1)),
196                        "Do not initial an ssl handshake with the server, talk in plaintext.")
197                ;
198}
199
200void NRPEClient::setup(client::configuration &config) {
201        boost::shared_ptr<clp_handler_impl> handler = boost::shared_ptr<clp_handler_impl>(new clp_handler_impl(this));
202        add_local_options(config.local, config.data);
203
204        config.data->recipient.address = net::parse("nrpe://localhost:5666");
205        std::wstring recipient = utf8::cvt<std::wstring>(config.data->recipient.id);
206        if (!targets.has_object(recipient)) {
207                NSC_LOG_ERROR(_T("Target not found (using default): ") + recipient);
208                recipient = _T("default");
209        }
210        nscapi::targets::optional_target_object opt = targets.find_object(recipient);
211
212        if (opt) {
213                nscapi::targets::target_object t = *opt;
214                nscapi::functions::destination_container def = t.to_destination_container();
215                config.data->recipient.apply(def);
216        }
217        config.data->recipient.id = "default";
218        config.data->host_self.id = "self";
219        //config.data->host_self.host = hostname_;
220
221        config.target_lookup = handler;
222        config.handler = handler;
223}
224
225NRPEClient::connection_data NRPEClient::parse_header(const ::Plugin::Common_Header &header, client::configuration::data_type data) {
226        nscapi::functions::destination_container recipient;
227        nscapi::functions::parse_destination(header, header.recipient_id(), recipient, true);
228        return connection_data(recipient, data->recipient);
229}
230
231//////////////////////////////////////////////////////////////////////////
232// Parser implementations
233//
234
235int NRPEClient::clp_handler_impl::query(client::configuration::data_type data, ::Plugin::Common_Header* header, const std::string &request, std::string &reply) {
236        Plugin::QueryRequestMessage request_message;
237        request_message.ParseFromString(request);
238        connection_data con = this->instance->parse_header(*header, data);
239
240        Plugin::QueryResponseMessage response_message;
241        nscapi::functions::make_return_header(response_message.mutable_header(), *header);
242
243        for (int i=0;i<request_message.payload_size();i++) {
244                std::string command = get_command(request_message.payload(i).alias(), request_message.payload(i).command());
245                std::string data = command;
246                for (int a=0;a<request_message.payload(i).arguments_size();a++) {
247                        data += "!" + request_message.payload(i).arguments(a);
248                }
249                boost::tuple<int,std::wstring> ret = instance->send(con, data);
250                std::pair<std::wstring,std::wstring> rdata = strEx::split(ret.get<1>(), std::wstring(_T("|")));
251                nscapi::functions::append_simple_query_response_payload(response_message.add_payload(), utf8::cvt<std::wstring>(command), ret.get<0>(), rdata.first, rdata.second);
252        }
253        response_message.SerializeToString(&reply);
254        return NSCAPI::isSuccess;
255}
256
257int NRPEClient::clp_handler_impl::submit(client::configuration::data_type data, ::Plugin::Common_Header* header, const std::string &request, std::string &reply) {
258        Plugin::SubmitRequestMessage request_message;
259        request_message.ParseFromString(request);
260        connection_data con = this->instance->parse_header(*header, data);
261        std::wstring channel = utf8::cvt<std::wstring>(request_message.channel());
262       
263        Plugin::SubmitResponseMessage response_message;
264        nscapi::functions::make_return_header(response_message.mutable_header(), *header);
265
266        for (int i=0;i<request_message.payload_size();++i) {
267                std::string command = get_command(request_message.payload(i).alias(), request_message.payload(i).command());
268                std::string data = command;
269                for (int a=0;a<request_message.payload(i).arguments_size();a++) {
270                        data += "!" + request_message.payload(i).arguments(i);
271                }
272                boost::tuple<int,std::wstring> ret = instance->send(con, data);
273                nscapi::functions::append_simple_submit_response_payload(response_message.add_payload(), command, ret.get<0>(), utf8::cvt<std::string>(ret.get<1>()));
274        }
275        response_message.SerializeToString(&reply);
276        return NSCAPI::isSuccess;
277}
278
279int NRPEClient::clp_handler_impl::exec(client::configuration::data_type data, ::Plugin::Common_Header* header, const std::string &request, std::string &reply) {
280        Plugin::ExecuteRequestMessage request_message;
281        request_message.ParseFromString(request);
282        connection_data con = this->instance->parse_header(*header, data);
283
284        Plugin::ExecuteResponseMessage response_message;
285        nscapi::functions::make_return_header(response_message.mutable_header(), *header);
286
287        for (int i=0;i<request_message.payload_size();i++) {
288                std::string command = get_command(request_message.payload(i).command());
289                std::string data = command;
290                for (int a=0;a<request_message.payload(i).arguments_size();a++)
291                        data += "!" + request_message.payload(i).arguments(a);
292                boost::tuple<int,std::wstring> ret = instance->send(con, data);
293                nscapi::functions::append_simple_exec_response_payload(response_message.add_payload(), command, ret.get<0>(), utf8::cvt<std::string>(ret.get<1>()));
294        }
295        response_message.SerializeToString(&reply);
296        return NSCAPI::isSuccess;
297}
298
299//////////////////////////////////////////////////////////////////////////
300// Protocol implementations
301//
302
303boost::tuple<int,std::wstring> NRPEClient::send(connection_data con, const std::string data) {
304        try {
305                NSC_DEBUG_MSG_STD(_T("NRPE Connection details: ") + con.to_wstring());
306                NSC_DEBUG_MSG_STD(_T("NRPE data: ") + utf8::cvt<std::wstring>(data));
307                nrpe::packet packet;
308                if (con.use_ssl) {
309#ifdef USE_SSL
310                        packet = send_ssl(con.cert, con.host, con.port, con.timeout, nrpe::packet::make_request(utf8::cvt<std::wstring>(data), con.buffer_length));
311#else
312                        NSC_LOG_ERROR_STD(_T("SSL not avalible (compiled without USE_SSL)"));
313                        return boost::make_tuple(NSCAPI::returnUNKNOWN, _T("SSL support not available (compiled without USE_SSL)"));
314#endif
315                } else
316                        packet = send_nossl(con.host, con.port, con.timeout, nrpe::packet::make_request(utf8::cvt<std::wstring>(data), con.buffer_length));
317                return boost::make_tuple(static_cast<int>(packet.getResult()), packet.getPayload());
318        } catch (nrpe::nrpe_packet_exception &e) {
319                return boost::make_tuple(NSCAPI::returnUNKNOWN, _T("NRPE Packet errro: ") + e.wwhat());
320        } catch (std::runtime_error &e) {
321                NSC_LOG_ERROR_STD(_T("Socket error: ") + utf8::to_unicode(e.what()));
322                return boost::make_tuple(NSCAPI::returnUNKNOWN, _T("Socket error: ") + utf8::to_unicode(e.what()));
323        } catch (std::exception &e) {
324                NSC_LOG_ERROR_STD(_T("Error: ") + utf8::to_unicode(e.what()));
325                return boost::make_tuple(NSCAPI::returnUNKNOWN, _T("Error: ") + utf8::to_unicode(e.what()));
326        } catch (...) {
327                return boost::make_tuple(NSCAPI::returnUNKNOWN, _T("Unknown error -- REPORT THIS!"));
328        }
329}
330
331
332#ifdef USE_SSL
333nrpe::packet NRPEClient::send_ssl(std::string cert, std::string host, std::string port, int timeout, nrpe::packet packet) {
334        boost::asio::io_service io_service;
335        boost::asio::ssl::context ctx(io_service, boost::asio::ssl::context::sslv23);
336        SSL_CTX_set_cipher_list(ctx.impl(), "ADH");
337        ctx.use_tmp_dh_file(to_string(cert));
338        ctx.set_verify_mode(boost::asio::ssl::context::verify_none);
339        nrpe::client::ssl_socket socket(io_service, ctx, host, port);
340        socket.send(packet, boost::posix_time::seconds(timeout));
341        return socket.recv(packet, boost::posix_time::seconds(timeout));
342}
343#endif
344
345nrpe::packet NRPEClient::send_nossl(std::string host, std::string port, int timeout, nrpe::packet packet) {
346        boost::asio::io_service io_service;
347        nrpe::client::socket socket(io_service, host, port);
348        socket.send(packet, boost::posix_time::seconds(timeout));
349        return socket.recv(packet, boost::posix_time::seconds(timeout));
350}
351
352NSC_WRAP_DLL();
353NSC_WRAPPERS_MAIN_DEF(NRPEClient);
354NSC_WRAPPERS_IGNORE_MSG_DEF();
355NSC_WRAPPERS_HANDLE_CMD_DEF();
356NSC_WRAPPERS_CLI_DEF();
357NSC_WRAPPERS_HANDLE_NOTIFICATION_DEF();
358
Note: See TracBrowser for help on using the repository browser.