source: nscp/trunk/modules/NRPEListener/NRPEListener.cpp @ 3c35ad4

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

+ Added possibility to check many memory checks in one go, just stack type options.

type=paged type=physical etc...

  • Fixed a performance check bug in the last nightly.
  • Fixed a potential crash when a maleformed check-file-age command was issued. + Added support for more then and NSClient command
  • Property mode set to 100644
File size: 14.0 KB
Line 
1// CheckEventLog.cpp : Defines the entry point for the DLL application.
2//
3
4#include "stdafx.h"
5#include "NRPEListener.h"
6#include <strEx.h>
7#include <time.h>
8#include <config.h>
9#include "NRPEPacket.h"
10
11NRPEListener gNRPEListener;
12
13BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
14{
15        NSCModuleWrapper::wrapDllMain(hModule, ul_reason_for_call);
16        return TRUE;
17}
18
19NRPEListener::NRPEListener() : noPerfData_(false) {
20}
21NRPEListener::~NRPEListener() {
22}
23
24std::string getAllowedHosts() {
25        std::string ret = NSCModuleHelper::getSettingsString(NRPE_SECTION_TITLE, MAIN_ALLOWED_HOSTS, "");
26        if (ret.empty())
27                ret = NSCModuleHelper::getSettingsString(MAIN_SECTION_TITLE, MAIN_ALLOWED_HOSTS, MAIN_ALLOWED_HOSTS_DEFAULT);
28        return ret;
29}
30bool getCacheAllowedHosts() {
31        int val = NSCModuleHelper::getSettingsInt(NRPE_SECTION_TITLE, MAIN_ALLOWED_HOSTS_CACHE, -1);
32        if (val == -1)
33                val = NSCModuleHelper::getSettingsInt(MAIN_SECTION_TITLE, MAIN_ALLOWED_HOSTS_CACHE, MAIN_ALLOWED_HOSTS_CACHE_DEFAULT);
34        return val==1?true:false;
35}
36
37bool NRPEListener::loadModule() {
38        bUseSSL_ = NSCModuleHelper::getSettingsInt(NRPE_SECTION_TITLE, NRPE_SETTINGS_USE_SSL ,NRPE_SETTINGS_USE_SSL_DEFAULT)==1;
39        noPerfData_ = NSCModuleHelper::getSettingsInt(NRPE_SECTION_TITLE, NRPE_SETTINGS_PERFDATA,NRPE_SETTINGS_PERFDATA_DEFAULT)==0;
40        timeout = NSCModuleHelper::getSettingsInt(NRPE_SECTION_TITLE, NRPE_SETTINGS_TIMEOUT ,NRPE_SETTINGS_TIMEOUT_DEFAULT);
41        std::list<std::string> commands = NSCModuleHelper::getSettingsSection(NRPE_HANDLER_SECTION_TITLE);
42        std::list<std::string>::const_iterator it;
43        for (it = commands.begin(); it != commands.end(); ++it) {
44                std::string command_name;
45                if (((*it).length() > 7)&&((*it).substr(0,7) == "command")) {
46                        strEx::token t = strEx::getToken((*it), '[');
47                        t = strEx::getToken(t.second, ']');
48                        command_name = t.first;
49                } else {
50                        command_name = (*it);
51                }
52                std::string s = NSCModuleHelper::getSettingsString(NRPE_HANDLER_SECTION_TITLE, (*it), "");
53                if (command_name.empty() || s.empty()) {
54                        NSC_LOG_ERROR_STD("Invalid command definition: " + (*it));
55                } else {
56                        addCommand(command_name.c_str(), s);
57                }
58        }
59
60        allowedHosts.setAllowedHosts(strEx::splitEx(getAllowedHosts(), ","), getCacheAllowedHosts());
61        try {
62                unsigned short port = NSCModuleHelper::getSettingsInt(NRPE_SECTION_TITLE, NRPE_SETTINGS_PORT, NRPE_SETTINGS_PORT_DEFAULT);
63                std::string host = NSCModuleHelper::getSettingsString(NRPE_SECTION_TITLE, NRPE_SETTINGS_BINDADDR, NRPE_SETTINGS_BINDADDR_DEFAULT);
64                unsigned int backLog = NSCModuleHelper::getSettingsInt(NRPE_SECTION_TITLE, NRPE_SETTINGS_LISTENQUE, NRPE_SETTINGS_LISTENQUE_DEFAULT);
65                if (bUseSSL_) {
66                        socket_ssl_.setHandler(this);
67                        socket_ssl_.StartListener(host, port, backLog);
68                } else {
69                        socket_.setHandler(this);
70                        socket_.StartListener(host, port, backLog);
71                }
72        } catch (simpleSocket::SocketException e) {
73                NSC_LOG_ERROR_STD("Exception caught: " + e.getMessage());
74                return false;
75        } catch (simpleSSL::SSLException e) {
76                NSC_LOG_ERROR_STD("Exception caught: " + e.getMessage());
77                return false;
78        }
79
80        return true;
81}
82bool NRPEListener::unloadModule() {
83        try {
84                if (bUseSSL_) {
85                        socket_ssl_.removeHandler(this);
86                        if (socket_ssl_.hasListener())
87                                socket_ssl_.StopListener();
88                } else {
89                        socket_.removeHandler(this);
90                        if (socket_.hasListener())
91                                socket_.StopListener();
92                }
93        } catch (simpleSocket::SocketException e) {
94                NSC_LOG_ERROR_STD("Exception caught: " + e.getMessage());
95                return false;
96        } catch (simpleSSL::SSLException e) {
97                NSC_LOG_ERROR_STD("Exception caught: " + e.getMessage());
98                return false;
99        }
100        return true;
101}
102
103
104bool NRPEListener::hasCommandHandler() {
105        return true;
106}
107bool NRPEListener::hasMessageHandler() {
108        return false;
109}
110
111
112NSCAPI::nagiosReturn NRPEListener::handleCommand(const strEx::blindstr command, const unsigned int argLen, char **char_args, std::string &message, std::string &perf) {
113        commandList::iterator it = commands.find(command);
114        if (it == commands.end())
115                return NSCAPI::returnIgnored;
116
117        std::string str = (*it).second;
118        if (NSCModuleHelper::getSettingsInt(NRPE_SECTION_TITLE, NRPE_SETTINGS_ALLOW_ARGUMENTS, NRPE_SETTINGS_ALLOW_ARGUMENTS_DEFAULT) == 1) {
119                arrayBuffer::arrayList arr = arrayBuffer::arrayBuffer2list(argLen, char_args);
120                arrayBuffer::arrayList::const_iterator cit = arr.begin();
121                int i=1;
122
123                for (;cit!=arr.end();cit++,i++) {
124                        if (NSCModuleHelper::getSettingsInt(NRPE_SECTION_TITLE, NRPE_SETTINGS_ALLOW_NASTY_META, NRPE_SETTINGS_ALLOW_NASTY_META_DEFAULT) == 0) {
125                                if ((*cit).find_first_of(NASTY_METACHARS) != std::string::npos) {
126                                        NSC_LOG_ERROR("Request string contained illegal metachars!");
127                                        return NSCAPI::returnIgnored;
128                                }
129                        }
130                        strEx::replace(str, "$ARG" + strEx::itos(i) + "$", (*cit));
131                }
132        }
133
134        if ((str.length() > 7)&&(str.substr(0,6) == "inject")) {
135                strEx::token t = strEx::getToken(str.substr(7), ' ');
136                std::string s = t.second;
137                std::string sTarget;
138
139                std::string::size_type p = 0;
140                while(true) {
141                        std::string::size_type pStart = p;
142                        std::string::size_type pEnd = std::string::npos;
143                        if (s[p] == '\"') {
144                                pStart++;
145                                while (true) {
146                                        p = s.find(' ', ++p);
147                                        if (p == std::string::npos)
148                                                break;
149                                        if ((p>1)&&(s[p-1]=='\"')&&(((p>2)&&(s[p-2]!='\\'))||(p==2)))
150                                                break;
151                                }
152                                if (p != std::string::npos)
153                                        pEnd = p-1;
154                                else
155                                        pEnd = s.length()-1;
156                                if (p != std::string::npos) {
157                                        p++;
158                                }
159                        } else {
160                                pEnd = p = s.find(' ', ++p);
161                                if (p != std::string::npos) {
162                                        p = s.find_first_not_of(' ', p);
163                                }
164                        }
165                        if (!sTarget.empty())
166                                sTarget += "!";
167                        if (p == std::string::npos) {
168                                if (pEnd == std::string::npos)
169                                        sTarget += s.substr(pStart);
170                                else
171                                        sTarget += s.substr(pStart, pEnd-pStart);
172                                break;
173                        }
174                        sTarget += s.substr(pStart,pEnd-pStart);
175                        //p++;
176                }
177                return NSCModuleHelper::InjectSplitAndCommand(t.first, sTarget, '!', message, perf);
178        }
179
180        return executeNRPECommand(str, message, perf);
181}
182#define MAX_INPUT_BUFFER 1024
183
184int NRPEListener::executeNRPECommand(std::string command, std::string &msg, std::string &perf)
185{
186        NSCAPI::nagiosReturn result;
187        PROCESS_INFORMATION pi;
188        STARTUPINFO si;
189        HANDLE hChildOutR, hChildOutW, hChildInR, hChildInW;
190        SECURITY_ATTRIBUTES sec;
191        DWORD dwstate, dwexitcode;
192        int retval;
193
194
195        // Set up members of SECURITY_ATTRIBUTES structure.
196
197        sec.nLength = sizeof(SECURITY_ATTRIBUTES);
198        sec.bInheritHandle = TRUE;
199        sec.lpSecurityDescriptor = NULL;
200
201        // Create Pipes
202        CreatePipe(&hChildInR, &hChildInW, &sec, 0);
203        CreatePipe(&hChildOutR, &hChildOutW, &sec, 0);
204
205        // Set up members of STARTUPINFO structure.
206
207        ZeroMemory(&si, sizeof(STARTUPINFO));
208        si.cb = sizeof(STARTUPINFO);
209        si.dwFlags = STARTF_USESTDHANDLES;
210        si.hStdInput = hChildInR;
211        si.hStdOutput = hChildOutW;
212        si.hStdError = hChildOutW;
213
214
215        // CreateProcess doesn't work with a const command
216        char *cmd = new char[command.length()+1];
217        strncpy(cmd, command.c_str(), command.length());
218        cmd[command.length()] = 0;
219
220        // Create the child process.
221        BOOL processOK = CreateProcess(NULL, cmd,        // command line
222                NULL, // process security attributes
223                NULL, // primary thread security attributes
224                TRUE, // handles are inherited
225                0,    // creation flags
226                NULL, // use parent's environment
227                NULL, // use parent's current directory
228                &si,  // STARTUPINFO pointer
229                &pi); // receives PROCESS_INFORMATION
230        delete [] cmd;
231
232        if (processOK) {
233                dwstate = WaitForSingleObject(pi.hProcess, 1000*timeout);
234                CloseHandle(hChildInR);
235                CloseHandle(hChildInW);
236                CloseHandle(hChildOutW);
237
238                if (dwstate == WAIT_TIMEOUT) {
239                        TerminateProcess(pi.hProcess, 5);
240                        msg = "The check didn't respond within the timeout period!";
241                        result = NSCAPI::returnUNKNOWN;
242                } else {
243                        DWORD dwread;
244                        char *buf = new char[MAX_INPUT_BUFFER+1];
245                        retval = ReadFile(hChildOutR, buf, MAX_INPUT_BUFFER, &dwread, NULL);
246                        if (!retval || dwread == 0) {
247                                msg = "No output available from command...";
248                        } else {
249                                buf[dwread] = 0;
250                                msg = buf;
251                                strEx::token t = strEx::getToken(msg, '\n');
252                                t = strEx::getToken(t.first, '|');
253                                msg = t.first;
254                                perf = t.second;
255                        }
256                        delete [] buf;
257                        GetExitCodeProcess(pi.hProcess, &dwexitcode);
258                        result = NSCHelper::int2nagios(dwexitcode);
259                }
260                CloseHandle(pi.hThread);
261                CloseHandle(pi.hProcess);
262                CloseHandle(hChildOutR);
263        }
264        else {
265                msg = "NRPE_NT failed to create process, exiting...";
266                result = NSCAPI::returnUNKNOWN;
267                CloseHandle(hChildInR);
268                CloseHandle(hChildInW);
269                CloseHandle(hChildOutW);
270                CloseHandle(pi.hThread);
271                CloseHandle(pi.hProcess);
272                CloseHandle(hChildOutR);
273        }
274        return result;
275}
276void NRPEListener::onClose()
277{}
278
279void NRPEListener::onAccept(simpleSocket::Socket *client)
280{
281        if (!allowedHosts.inAllowedHosts(client->getAddrString())) {
282                NSC_LOG_ERROR("Unothorized access from: " + client->getAddrString());
283                client->close();
284                return;
285        }
286        try {
287                simpleSocket::DataBuffer block;
288                int i;
289                for (i=0;i<100;i++) {
290                        client->readAll(block, 1048);
291                        if (block.getLength() >= NRPEPacket::getBufferLength())
292                                break;
293                        Sleep(100);
294                }
295                if (i == 100) {
296                        NSC_LOG_ERROR_STD("Could not retrieve NRPE packet.");
297                        client->close();
298                        return;
299                }
300                if (block.getLength() == NRPEPacket::getBufferLength()) {
301                        try {
302                                NRPEPacket out = handlePacket(NRPEPacket(block.getBuffer(), block.getLength()));
303                                block.copyFrom(out.getBuffer(), out.getBufferLength());
304                        } catch (NRPEPacket::NRPEPacketException e) {
305                                NSC_LOG_ERROR_STD("NRPESocketException: " + e.getMessage());
306                                client->close();
307                                return;
308                        }
309                        client->send(block);
310                }
311        } catch (simpleSocket::SocketException e) {
312                NSC_LOG_ERROR_STD("SocketException: " + e.getMessage());
313        } catch (NRPEException e) {
314                NSC_LOG_ERROR_STD("NRPEException: " + e.getMessage());
315        }
316        client->close();
317}
318
319NRPEPacket NRPEListener::handlePacket(NRPEPacket p) {
320        if (p.getType() != NRPEPacket::queryPacket) {
321                NSC_LOG_ERROR("Request is not a query.");
322                throw NRPEException("Invalid query type");
323        }
324        if (p.getVersion() != NRPEPacket::version2) {
325                NSC_LOG_ERROR("Request had unsupported version.");
326                throw NRPEException("Invalid version");
327        }
328        if (!p.verifyCRC()) {
329                NSC_LOG_ERROR("Request had invalid checksum.");
330                throw NRPEException("Invalid checksum");
331        }
332        strEx::token cmd = strEx::getToken(p.getPayload(), '!');
333        if (cmd.first == "_NRPE_CHECK") {
334                return NRPEPacket(NRPEPacket::responsePacket, NRPEPacket::version2, NSCAPI::returnOK, "I ("SZVERSION") seem to be doing fine...");
335        }
336        std::string msg, perf;
337
338        if (NSCModuleHelper::getSettingsInt(NRPE_SECTION_TITLE, NRPE_SETTINGS_ALLOW_ARGUMENTS, NRPE_SETTINGS_ALLOW_ARGUMENTS_DEFAULT) == 0) {
339                if (!cmd.second.empty()) {
340                        NSC_LOG_ERROR("Request contained arguments (not currently allowed, check the allow_arguments option).");
341                        throw NRPEException("Request contained arguments (not currently allowed, check the allow_arguments option).");
342                }
343        }
344        if (NSCModuleHelper::getSettingsInt(NRPE_SECTION_TITLE, NRPE_SETTINGS_ALLOW_NASTY_META, NRPE_SETTINGS_ALLOW_NASTY_META_DEFAULT) == 0) {
345                if (cmd.first.find_first_of(NASTY_METACHARS) != std::string::npos) {
346                        NSC_LOG_ERROR("Request command contained illegal metachars!");
347                        throw NRPEException("Request command contained illegal metachars!");
348                }
349                if (cmd.second.find_first_of(NASTY_METACHARS) != std::string::npos) {
350                        NSC_LOG_ERROR("Request arguments contained illegal metachars!");
351                        throw NRPEException("Request command contained illegal metachars!");
352                }
353        }
354
355        NSCAPI::nagiosReturn ret = NSCModuleHelper::InjectSplitAndCommand(cmd.first, cmd.second, '!', msg, perf);
356        switch (ret) {
357                case NSCAPI::returnInvalidBufferLen:
358                        msg = "UNKNOWN: Return buffer to small to handle this command.";
359                        ret = NSCAPI::returnUNKNOWN;
360                        break;
361                case NSCAPI::returnIgnored:
362                        msg = "UNKNOWN: No handler for that command";
363                        ret = NSCAPI::returnUNKNOWN;
364                        break;
365                case NSCAPI::returnOK:
366                case NSCAPI::returnWARN:
367                case NSCAPI::returnCRIT:
368                case NSCAPI::returnUNKNOWN:
369                        break;
370                default:
371                        msg = "UNKNOWN: Internal error.";
372                        ret = NSCAPI::returnUNKNOWN;
373        }
374        if (perf.empty()||noPerfData_) {
375                return NRPEPacket(NRPEPacket::responsePacket, NRPEPacket::version2, ret, msg);
376        } else {
377                return NRPEPacket(NRPEPacket::responsePacket, NRPEPacket::version2, ret, msg + "|" + perf);
378        }
379}
380
381NSC_WRAPPERS_MAIN_DEF(gNRPEListener);
382NSC_WRAPPERS_IGNORE_MSG_DEF();
383NSC_WRAPPERS_HANDLE_CMD_DEF(gNRPEListener);
384NSC_WRAPPERS_HANDLE_CONFIGURATION(gNRPEListener);
385
386
387MODULE_SETTINGS_START(NRPEListener, "NRPE Listsner configuration", "...")
388
389PAGE("NRPE Listsner configuration")
390
391ITEM_EDIT_TEXT("port", "This is the port the NRPEListener.dll will listen to.")
392ITEM_MAP_TO("basic_ini_text_mapper")
393OPTION("section", "NRPE")
394OPTION("key", "port")
395OPTION("default", "5666")
396ITEM_END()
397
398ITEM_CHECK_BOOL("allow_arguments", "This option determines whether or not the NRPE daemon will allow clients to specify arguments to commands that are executed.")
399ITEM_MAP_TO("basic_ini_bool_mapper")
400OPTION("section", "NRPE")
401OPTION("key", "allow_arguments")
402OPTION("default", "false")
403OPTION("true_value", "1")
404OPTION("false_value", "0")
405ITEM_END()
406
407ITEM_CHECK_BOOL("allow_nasty_meta_chars", "This might have security implications (depending on what you do with the options)")
408ITEM_MAP_TO("basic_ini_bool_mapper")
409OPTION("section", "NRPE")
410OPTION("key", "allow_nasty_meta_chars")
411OPTION("default", "false")
412OPTION("true_value", "1")
413OPTION("false_value", "0")
414ITEM_END()
415
416ITEM_CHECK_BOOL("use_ssl", "This option will enable SSL encryption on the NRPE data socket (this increases security somwhat.")
417ITEM_MAP_TO("basic_ini_bool_mapper")
418OPTION("section", "NRPE")
419OPTION("key", "use_ssl")
420OPTION("default", "true")
421OPTION("true_value", "1")
422OPTION("false_value", "0")
423ITEM_END()
424
425PAGE_END()
426ADVANCED_PAGE("Access configuration")
427
428ITEM_EDIT_OPTIONAL_LIST("Allow connection from:", "This is the hosts that will be allowed to poll performance data from the NRPE server.")
429OPTION("disabledCaption", "Use global settings (defined previously)")
430OPTION("enabledCaption", "Specify hosts for NRPE server")
431OPTION("listCaption", "Add all IP addresses (not hosts) which should be able to connect:")
432OPTION("separator", ",")
433OPTION("disabled", "")
434ITEM_MAP_TO("basic_ini_text_mapper")
435OPTION("section", "NRPE")
436OPTION("key", "allowed_hosts")
437OPTION("default", "")
438ITEM_END()
439
440PAGE_END()
441MODULE_SETTINGS_END()
Note: See TracBrowser for help on using the repository browser.