source: nscp/modules/NSClientListener/NSClientListener.cpp @ dc59b0e

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

2008-09-07 MickeM

+ Added sample powershell script as well as a workaround for making them run.

  • Fixed an issue making powershell scripts (and possibly others) not timeout properly. + Added upgrade support to the installer (still need to add support for keeping .ini file so be ware)
  • Property mode set to 100644
File size: 13.0 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 "NSClientListener.h"
23#include <strEx.h>
24#include <time.h>
25#include <config.h>
26
27NSClientListener gNSClientListener;
28
29
30#define REQ_CLIENTVERSION       1       // Works fine!
31#define REQ_CPULOAD                     2       // Quirks
32#define REQ_UPTIME                      3       // Works fine!
33#define REQ_USEDDISKSPACE       4       // Works fine!
34#define REQ_SERVICESTATE        5       // Works fine!
35#define REQ_PROCSTATE           6       // Works fine!
36#define REQ_MEMUSE                      7       // Works fine!
37#define REQ_COUNTER                     8       // Works fine!
38#define REQ_FILEAGE                     9       // ... in the works ...
39//#define REQ_INSTANCES 10      // ! - not implemented Don't know how to use
40
41BOOL APIENTRY DllMain( HANDLE hModule, DWORD  ul_reason_for_call, LPVOID lpReserved)
42{
43        NSCModuleWrapper::wrapDllMain(hModule, ul_reason_for_call);
44        return TRUE;
45}
46
47NSClientListener::NSClientListener() {
48}
49NSClientListener::~NSClientListener() {
50}
51std::wstring getAllowedHosts() {
52        std::wstring ret = NSCModuleHelper::getSettingsString(NSCLIENT_SECTION_TITLE, MAIN_ALLOWED_HOSTS, _T(""));
53        if (ret.empty())
54                ret = NSCModuleHelper::getSettingsString(MAIN_SECTION_TITLE, MAIN_ALLOWED_HOSTS, MAIN_ALLOWED_HOSTS_DEFAULT);
55        return ret;
56}
57bool getCacheAllowedHosts() {
58        int val = NSCModuleHelper::getSettingsInt(NSCLIENT_SECTION_TITLE, MAIN_ALLOWED_HOSTS_CACHE, -1);
59        if (val == -1)
60                val = NSCModuleHelper::getSettingsInt(MAIN_SECTION_TITLE, MAIN_ALLOWED_HOSTS_CACHE, MAIN_ALLOWED_HOSTS_CACHE_DEFAULT);
61        return val==1?true:false;
62}
63
64bool NSClientListener::loadModule() {
65        allowedHosts.setAllowedHosts(strEx::splitEx(getAllowedHosts(), _T(",")), getCacheAllowedHosts());
66        unsigned short port = NSCModuleHelper::getSettingsInt(NSCLIENT_SECTION_TITLE, NSCLIENT_SETTINGS_PORT, NSCLIENT_SETTINGS_PORT_DEFAULT);
67        std::wstring host = NSCModuleHelper::getSettingsString(NSCLIENT_SECTION_TITLE, NSCLIENT_SETTINGS_BINDADDR, NSCLIENT_SETTINGS_BINDADDR_DEFAULT);
68        unsigned int backLog = NSCModuleHelper::getSettingsInt(NSCLIENT_SECTION_TITLE, NSCLIENT_SETTINGS_LISTENQUE, NSCLIENT_SETTINGS_LISTENQUE_DEFAULT);
69        socketTimeout_ = NSCModuleHelper::getSettingsInt(NSCLIENT_SECTION_TITLE, NSCLIENT_SETTINGS_READ_TIMEOUT, NSCLIENT_SETTINGS_READ_TIMEOUT_DEFAULT);
70        try {
71                socket.setHandler(this);
72                socket.StartListener(host, port, backLog);
73        } catch (simpleSocket::SocketException e) {
74                NSC_LOG_ERROR_STD(_T("Exception caught: ") + e.getMessage());
75                return false;
76        }
77        return true;
78}
79bool NSClientListener::unloadModule() {
80        try {
81                socket.removeHandler(this);
82                if (socket.hasListener())
83                        socket.StopListener();
84        } catch (simpleSocket::SocketException e) {
85                NSC_LOG_ERROR_STD(_T("Exception caught: ") + e.getMessage());
86                return false;
87        }
88        return true;
89}
90
91/**
92* Main command parser and delegator.
93* This also handles a lot of the simpler responses (though some are deferred to other helper functions)
94*
95#define REQ_CLIENTVERSION       1       // Works fine!
96#define REQ_CPULOAD             2       // Quirks
97- Needs settings for default buffer size (backlog) and possibly other things.
98- Buffer needs to be synced with the client (don't know the size of that)
99- I think the idea was that the buffer would recursive to make a smaller memory footprint.
100(ie. the first level buffer have samples from every second, next level samples from every minute, next level hours etc...)
101(and I don't know the status of this, doesn't seem to be that way)
102#define REQ_UPTIME                      3       // Works fine!
103#define REQ_USEDDISKSPACE       4       // Works fine!
104#define REQ_SERVICESTATE        5       // Works fine!
105#define REQ_PROCSTATE           6       // Works fine!
106#define REQ_MEMUSE                      7       // Works fine!
107//#define REQ_COUNTER           8       // ! - not implemented Have to look at this, if anyone has a sample let me know...
108//#define REQ_FILEAGE           9       // ! - not implemented Don't know how to use
109//#define REQ_INSTANCES 10      // ! - not implemented Don't know how to use
110*
111*/
112
113
114std::wstring getPassword() {
115        static std::wstring password = _T("");
116        if (password.empty()) {
117                password = NSCModuleHelper::getSettingsString(NSCLIENT_SECTION_TITLE, MAIN_OBFUSCATED_PASWD, MAIN_OBFUSCATED_PASWD_DEFAULT);
118                if (password.empty())
119                        password= NSCModuleHelper::getSettingsString(MAIN_SECTION_TITLE, MAIN_OBFUSCATED_PASWD, MAIN_OBFUSCATED_PASWD_DEFAULT);
120                if (!password.empty()) {
121                        password = NSCModuleHelper::Decrypt(password);
122                } else {
123                        password = NSCModuleHelper::getSettingsString(NSCLIENT_SECTION_TITLE, MAIN_SETTINGS_PWD, MAIN_SETTINGS_PWD_DEFAULT);
124                        if (password.empty())
125                                password = NSCModuleHelper::getSettingsString(MAIN_SECTION_TITLE, MAIN_SETTINGS_PWD, MAIN_SETTINGS_PWD_DEFAULT);
126                }
127        }
128        return password;
129}
130bool NSClientListener::isPasswordOk(std::wstring remotePassword)  {
131        std::wstring localPassword = getPassword();
132        if (localPassword == remotePassword) {
133                return true;
134        }
135        if ((remotePassword == _T("None")) && (localPassword.empty())) {
136                return true;
137        }
138        return false;
139}
140
141std::string NSClientListener::parseRequest(std::string str_buffer)  {
142        std::wstring buffer = strEx::string_to_wstring(str_buffer);
143        NSC_DEBUG_MSG_STD(_T("Data: ") + buffer);
144
145        std::wstring::size_type pos = buffer.find_first_of(_T("\n\r"));
146        if (pos != std::wstring::npos) {
147                std::wstring::size_type pos2 = buffer.find_first_not_of(_T("\n\r"), pos);
148                if (pos2 != std::wstring::npos) {
149                        std::wstring rest = buffer.substr(pos2);
150                        NSC_DEBUG_MSG_STD(_T("Ignoring data: ") + rest);
151                }
152                buffer = buffer.substr(0, pos);
153        }
154
155        strEx::token pwd = strEx::getToken(buffer, '&');
156        if (!isPasswordOk(pwd.first)) {
157                NSC_LOG_ERROR_STD(_T("Invalid password (") + pwd.first + _T(")."));
158                return "ERROR: Invalid password.";
159        }
160        if (pwd.second.empty())
161                return "ERROR: No command specified.";
162        strEx::token cmd = strEx::getToken(pwd.second, '&');
163        if (cmd.first.empty())
164                return "ERROR: No command specified.";
165
166        int c = _wtoi(cmd.first.c_str());
167
168        NSC_DEBUG_MSG_STD(_T("Data: ") + cmd.second);
169
170
171        // prefix various commands
172        switch (c) {
173                case REQ_CPULOAD:
174                        cmd.first = _T("checkCPU");
175                        cmd.second += _T("&nsclient");
176                        break;
177                case REQ_UPTIME:
178                        cmd.first = _T("checkUpTime");
179                        cmd.second = _T("nsclient");
180                        break;
181                case REQ_USEDDISKSPACE:
182                        cmd.first = _T("CheckDriveSize");
183                        cmd.second += _T("&nsclient");
184                        break;
185                case REQ_CLIENTVERSION:
186                        {
187                                std::wstring v = NSCModuleHelper::getSettingsString(NSCLIENT_SECTION_TITLE, NSCLIENT_SETTINGS_VERSION, NSCLIENT_SETTINGS_VERSION_DEFAULT);
188                                if (v == _T("auto"))
189                                        v = NSCModuleHelper::getApplicationName() + _T(" ") + NSCModuleHelper::getApplicationVersionString();
190                                return strEx::wstring_to_string(v);
191                        }
192                case REQ_SERVICESTATE:
193                        cmd.first = _T("checkServiceState");
194                        cmd.second += _T("&nsclient");
195                        break;
196                case REQ_PROCSTATE:
197                        cmd.first = _T("checkProcState");
198                        cmd.second += _T("&nsclient");
199                        break;
200                case REQ_MEMUSE:
201                        cmd.first = _T("checkMem");
202                        cmd.second = _T("nsclient");
203                        break;
204                case REQ_COUNTER:
205                        cmd.first = _T("checkCounter");
206                        cmd.second = _T("Counter=") + cmd.second + _T("&nsclient");
207                        break;
208                case REQ_FILEAGE:
209                        cmd.first = _T("getFileAge");
210                        cmd.second = _T("path=") + cmd.second;
211                        break;
212        }
213
214        std::wstring message, perf;
215        NSCAPI::nagiosReturn ret = NSCModuleHelper::InjectSplitAndCommand(cmd.first.c_str(), cmd.second.c_str(), '&', message, perf);
216        if (!NSCHelper::isNagiosReturnCode(ret)) {
217                if (message.empty())
218                        return "ERROR: Could not complete the request check log file for more information.";
219                return "ERROR: " + strEx::wstring_to_string(message);
220        }
221        switch (c) {
222                case REQ_UPTIME:                // Some check_nt commands has no return code syntax
223                case REQ_MEMUSE:
224                case REQ_CPULOAD:
225                case REQ_CLIENTVERSION:
226                case REQ_USEDDISKSPACE:
227                case REQ_COUNTER:
228                case REQ_FILEAGE:
229                        return strEx::wstring_to_string(message);
230
231                case REQ_SERVICESTATE:  // Some check_nt commands return the return code (coded as a string)
232                case REQ_PROCSTATE:
233                        return strEx::wstring_to_string(strEx::itos(NSCHelper::nagios2int(ret)) + _T("& ") + message);
234
235                default:                                // "New" check_nscp also returns performance data
236                        if (perf.empty())
237                                return strEx::wstring_to_string(NSCHelper::translateReturn(ret) + _T("&") + message);
238                        return strEx::wstring_to_string(NSCHelper::translateReturn(ret) + _T("&") + message + _T("&") + perf);
239        }
240}
241
242void NSClientListener::onClose()
243{}
244
245void NSClientListener::sendTheResponse(simpleSocket::Socket *client, std::string response) {
246        client->send(response.c_str(), static_cast<int>(response.length()), 0);
247}
248
249void NSClientListener::retrivePacket(simpleSocket::Socket *client) {
250        simpleSocket::DataBuffer db;
251        unsigned int i;
252        unsigned int maxWait = socketTimeout_*10;
253        for (i=0;i<maxWait;i++) {
254                bool lastReadHasMore = false;
255                try {
256                        lastReadHasMore = client->readAll(db);
257                } catch (simpleSocket::SocketException e) {
258                        NSC_LOG_ERROR_STD(_T("Read on socket failed: ") + e.getMessage());
259                        client->close();
260                        return;
261                }
262                if (db.getLength() > 0) {
263                        unsigned long long pos = db.find('\n');
264                        if (pos==-1) {
265                                std::string incoming(db.getBuffer(), db.getLength());
266                                sendTheResponse(client, parseRequest(incoming));
267                                break;
268                        } else if (pos>0) {
269                                simpleSocket::DataBuffer buffer = db.unshift(static_cast<const unsigned int>(pos));
270                                std::string bstr(buffer.getBuffer(), buffer.getLength());
271                                db.nibble(1);
272                                std::string rstr(db.getBuffer(), db.getLength());
273                                std::string incoming(buffer.getBuffer(), buffer.getLength());
274                                sendTheResponse(client, parseRequest(incoming) + "\n");
275                        } else {
276                                db.nibble(1);
277                                NSC_LOG_ERROR_STD(_T("First char should (i think) not be a \\n :("));
278                        }
279                } else if (!lastReadHasMore) {
280                        client->close();
281                        return;
282                } else {
283                        Sleep(100);
284                }
285        }
286        if (i >= maxWait) {
287                NSC_LOG_ERROR_STD(_T("Timeout reading NS-client packet (increase socket_timeout)."));
288                client->close();
289                return;
290        }
291}
292
293
294void NSClientListener::onAccept(simpleSocket::Socket *client) {
295        if (!allowedHosts.inAllowedHosts(client->getAddr())) {
296                NSC_LOG_ERROR(_T("Unauthorized access from: ") + client->getAddrString());
297                client->close();
298                return;
299        }
300        //client->setNonBlock();
301        retrivePacket(client);
302
303
304
305//      client->readAll(db);
306//      if (db.getLength() > 0) {
307//              std::wstring incoming(db.getBuffer(), db.getLength());
308//              NSC_DEBUG_MSG_STD("Incoming data: " + incoming);
309//              std::wstring response = parseRequest(incoming);
310//              NSC_DEBUG_MSG("Outgoing data: " + response);
311//              client->send(response.c_str(), static_cast<int>(response.length()), 0);
312//      }
313        client->close();
314}
315
316NSC_WRAPPERS_MAIN_DEF(gNSClientListener);
317NSC_WRAPPERS_IGNORE_MSG_DEF();
318NSC_WRAPPERS_IGNORE_CMD_DEF();
319NSC_WRAPPERS_HANDLE_CONFIGURATION(gNSClientListener);
320
321
322MODULE_SETTINGS_START(NSClientListener, _T("NSClient Listener configuration"), _T("..."))
323
324PAGE(_T("NSClient Listener configuration"))
325
326ITEM_EDIT_TEXT(_T("port"), _T("This is the port the NSClientListener.dll will listen to."))
327ITEM_MAP_TO(_T("basic_ini_text_mapper"))
328OPTION(_T("section"), _T("NSClient"))
329OPTION(_T("key"), _T("port"))
330OPTION(_T("default"), _T("12489"))
331ITEM_END()
332
333PAGE_END()
334ADVANCED_PAGE(_T("Server settings"))
335
336ITEM_EDIT_TEXT(_T("password"), _T("Enter the password used by applications when queriying for data."))
337ITEM_MAP_TO(_T("basic_ini_text_mapper"))
338OPTION(_T("section"), _T("NSClient"))
339OPTION(_T("key"), _T("password"))
340OPTION(_T("default"), _T(""))
341ITEM_END()
342
343ITEM_EDIT_OPTIONAL_LIST(_T("Allow connection from:"), _T("This is the hosts that will be allowed to poll performance data from the server."))
344OPTION(_T("disabledCaption"), _T("Use global settings (defined previously)"))
345OPTION(_T("enabledCaption"), _T("Specify hosts for NSClient server"))
346OPTION(_T("listCaption"), _T("Add all IP addresses (not hosts) which should be able to connect:"))
347OPTION(_T("separator"), _T(","))
348OPTION(_T("disabled"), _T(""))
349ITEM_MAP_TO(_T("basic_ini_text_mapper"))
350OPTION(_T("section"), _T("NSClient"))
351OPTION(_T("key"), _T("allowed_hosts"))
352OPTION(_T("default"), _T(""))
353ITEM_END()
354
355PAGE_END()
356MODULE_SETTINGS_END()
Note: See TracBrowser for help on using the repository browser.