source: nscp/modules/NRPEListener/NRPEListener.cpp @ 76aafc4

0.4.00.4.10.4.2stable
Last change on this file since 76aafc4 was 76aafc4, checked in by Michael Medin <michael@…>, 7 years ago

* empty log message *

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