source: nscp/trunk/NSClient++.cpp @ 079055f

Last change on this file since 079055f was 079055f, checked in by Michael Medin <michael@…>, 8 years ago

Verified NSCLient compatiblity for many commands and some minor tweaks (now most NSClient commands are OK)

  • Property mode set to 100644
File size: 11.4 KB
Line 
1//////////////////////////////////////////////////////////////////////////
2// NSClient++ Base Service
3//
4// Copyright (c) 2004 MySolutions NORDIC (http://www.medin.name)
5//
6// Date: 2004-03-13
7// Author: Michael Medin (michael@medin.name)
8//
9// Part of this file is based on work by Bruno Vais (bvais@usa.net)
10//
11// This software is provided "AS IS", without a warranty of any kind.
12// You are free to use/modify this code but leave this header intact.
13//
14//////////////////////////////////////////////////////////////////////////
15#include "stdafx.h"
16#include <winsvc.h>
17#include "NSClient++.h"
18#include "Settings.h"
19#include <charEx.h>
20
21NSClient mainClient;    // Global core instance.
22
23//////////////////////////////////////////////////////////////////////////
24// Startup code
25
26/**
27 * Application startup point
28 *
29 * @param argc Argument count
30 * @param argv[] Argument array
31 * @param envp[] Environment array
32 * @return exit status
33 */
34int main(int argc, TCHAR* argv[], TCHAR* envp[])
35{
36        int nRetCode = 0;
37
38        if ( (argc > 1) && ((*argv[1] == '-') || (*argv[1] == '/')) ) {
39                if ( _stricmp( "install", argv[1]+1 ) == 0 ) {
40                        try {
41                                serviceControll::Install(SZSERVICENAME, SZSERVICEDISPLAYNAME, SZDEPENDENCIES);
42                        } catch (const serviceControll::SCException& e) {
43                                LOG_MESSAGE_STD("Service installation failed: " + e.error_);
44                                return -1;
45                        }
46                        LOG_MESSAGE("Service installed!");
47                } else if ( _stricmp( "uninstall", argv[1]+1 ) == 0 ) {
48                        try {
49                                serviceControll::Uninstall(SZSERVICENAME);
50                        } catch (const serviceControll::SCException& e) {
51                                LOG_MESSAGE_STD("Service deinstallation failed; " + e.error_);
52                                return -1;
53                        }
54                } else if ( _stricmp( "start", argv[1]+1 ) == 0 ) {
55                        serviceControll::Start(SZSERVICENAME);
56                } else if ( _stricmp( "stop", argv[1]+1 ) == 0 ) {
57                        serviceControll::Stop(SZSERVICENAME);
58                } else if ( _stricmp( "about", argv[1]+1 ) == 0 ) {
59                        LOG_MESSAGE(SZAPPNAME " (C) Michael Medin");
60                        LOG_MESSAGE("Version " SZVERSION);
61                } else if ( _stricmp( "version", argv[1]+1 ) == 0 ) {
62                        LOG_MESSAGE(SZAPPNAME " Version: " SZVERSION);
63                } else if ( _stricmp( "test", argv[1]+1 ) == 0 ) {
64                        mainClient.InitiateService();
65                        LOG_MESSAGE("Enter command to inject or exit to terminate...");
66                        std::string s = "";
67                        std::cin >> s;
68                        while (s != "exit") {
69                                mainClient.inject(s);
70                                std::cin >> s;
71                        }
72                        mainClient.TerminateService();
73                        LOG_MESSAGE("DONE!");
74                        return 0;
75                } else {
76                        LOG_MESSAGE("Usage: -version, -about, -install, -uninstall, -start, -stop");
77                }
78                return nRetCode;
79        }
80        mainClient.StartServiceCtrlDispatcher();
81        return nRetCode;
82}
83
84//////////////////////////////////////////////////////////////////////////
85// Service functions
86
87/**
88 * Service control handler startup point.
89 * When the program is started as a service this will be the entry point.
90 */
91void NSClientT::InitiateService(void) {
92        Settings::getInstance()->setFile(getBasePath() + "NSC.ini");
93
94        SettingsT::sectionList list = Settings::getInstance()->getSection("modules");
95        for (SettingsT::sectionList::iterator it = list.begin(); it != list.end(); it++) {
96                try {
97                        LOG_DEBUG_STD("Loading: " + getBasePath() + "modules\\" + (*it));
98                        loadPlugin(getBasePath() + "modules\\" + (*it));
99                } catch(const NSPluginException& e) {
100                        LOG_ERROR_STD("Exception raised: " + e.error_ + " in module: " + e.file_);
101                }
102        }
103        socketThread.createThread();
104}
105/**
106 * Service control handler termination point.
107 * When the program is stopped as a service this will be the "exit point".
108 */
109void NSClientT::TerminateService(void) {
110        if (!socketThread.exitThread())
111                LOG_ERROR("Could not exit socket listener thread");
112        try {
113                LOG_DEBUG("Socket closed, unloading plugins...");
114                mainClient.unloadPlugins();
115                LOG_DEBUG("Plugins unloaded...");
116        } catch(NSPluginException *e) {
117                LOG_ERROR_STD("Exception raised: " + e->error_ + " in module: " + e->file_);
118        }
119        Settings::destroyInstance();
120}
121
122/**
123 * Forward this to the main service dispatcher helper class
124 * @param dwArgc
125 * @param *lpszArgv
126 */
127void WINAPI NSClientT::service_main_dispatch(DWORD dwArgc, LPTSTR *lpszArgv) {
128        mainClient.service_main(dwArgc, lpszArgv);
129}
130/**
131 * Forward this to the main service dispatcher helper class
132 * @param dwCtrlCode
133 */
134void WINAPI NSClientT::service_ctrl_dispatch(DWORD dwCtrlCode) {
135        mainClient.service_ctrl(dwCtrlCode);
136}
137
138//////////////////////////////////////////////////////////////////////////
139// Member functions
140
141
142/**
143 * Load a list of plug-ins
144 * @param plugins A list with plug-ins (DLL files) to load
145 */
146void NSClientT::loadPlugins(std::list<std::string> plugins) {
147        std::list<std::string>::const_iterator it;
148        for (it = plugins.begin(); it != plugins.end(); ++it) {
149                loadPlugin(*it);
150        }
151}
152/**
153 * Unload all plug-ins (in reversed order)
154 */
155void NSClientT::unloadPlugins() {
156        pluginList::reverse_iterator it;
157        for (it = plugins_.rbegin(); it != plugins_.rend(); ++it) {
158#ifdef _DEBUG
159                std::cout << "Unloading plugin: " << (*it)->getName() << "...";
160#endif
161                (*it)->unload();
162#ifdef _DEBUG
163                std::cout << "OK" << std::endl;
164#endif
165        }
166        messageHandlers_.clear();
167        commandHandlers_.clear();
168        for (it = plugins_.rbegin(); it != plugins_.rend(); ++it) {
169                delete (*it);
170        }
171        plugins_.clear();
172}
173/**
174 * Load a single plug-in using a DLL filename
175 * @param file The DLL file
176 */
177void NSClientT::loadPlugin(std::string file) {
178        addPlugin(new NSCPlugin(file));
179}
180/**
181 * Load and add a plugin to various internal structures
182 * @param *plugin The plug-ininstance to load. The pointer is managed by the
183 */
184void NSClientT::addPlugin(plugin_type plugin) {
185        plugin->load();
186        LOG_DEBUG_STD("Loading: " + plugin->getName());
187        // @todo Catch here and unload if we fail perhaps ?
188        plugins_.push_back(plugin);
189        if (plugin->hasCommandHandler())
190                commandHandlers_.push_back(plugin);
191        if (plugin->hasMessageHandler())
192                messageHandlers_.push_back(plugin);
193}
194/**
195 * Inject a command into the plug-in stack.
196 *
197 * @param buffer A command string to inject. This should be a unparsed command string such as command&arg1&arg2&arg...
198 * @return The result, empty string if no result
199 */
200std::string NSClientT::inject(std::string buffer) {
201        std::list<std::string> args = charEx::split(buffer.c_str(), '&');
202        if (args.size() < 2) {
203                LOG_MESSAGE("Insufficient arguments!");
204        }
205        std::string command = args.front(); args.pop_front();
206        LOG_MESSAGE_STD("Injecting: " + command);
207        std::string ret = execute(NSClientT::getPassword(), command, args);
208        LOG_MESSAGE_STD("Injected Result: " + ret);
209        return ret;
210
211}
212/**
213 * Helper function to return the current password (perhaps this should be static ?)
214 *
215 * @return The current password
216 */
217std::string NSClientT::getPassword() {
218        return Settings::getInstance()->getString("generic", "password", "");
219}
220/**
221 * Execute a command.
222 *
223 * @param password The password
224 * @param cmd The command
225 * @param args Arguments as a list<string>
226 * @return The result if any, empty string if no result.
227 *
228 * @todo Make an int return value to set critical/warning/ok/unknown status.
229 * ie. pair<int,string>
230 */
231std::string NSClientT::execute(std::string password, std::string cmd, std::list<std::string> args) {
232        static unsigned int bufferSize = 0;
233        if (bufferSize == 0)
234                bufferSize = static_cast<unsigned int>(Settings::getInstance()->getInt("main", "bufferSize", 4096));
235
236        if (password != getPassword())
237                return "INVALID PASSWORD";
238
239        // Pack the argument as a char** buffer
240        std::string ret;
241        int len = args.size();
242        char **arguments = new char*[len];
243        std::list<std::string>::iterator it = args.begin();
244        for (int i=0;it!=args.end();++it,i++) {
245                int alen = (*it).size();
246                arguments[i] = new char[alen+2];
247                strncpy(arguments[i], (*it).c_str(), alen+1);
248        }
249        // Allocate return buffer
250        char* returnbuffer = new char[bufferSize+1];
251        pluginList::const_iterator plit;
252        for (plit = commandHandlers_.begin(); plit != commandHandlers_.end(); ++plit) {
253                try {
254                        int c = (*plit)->handleCommand(cmd.c_str(), len, arguments, returnbuffer, bufferSize);
255                        if (c == NSCAPI::handled) {                                     // module handled the message "we are done..."
256                                ret = returnbuffer;
257                                break;
258                        } else if (c == NSCAPI::isfalse) {                      // Module ignored the message
259                        } else if (c == NSCAPI::invalidBufferLen) {     // Buffer is to small
260                                LOG_ERROR("Return buffer to small, need to increase it in the ini file.");
261                        } else {                                                                        // Something else went wrong...
262                                LOG_ERROR_STD("Unknown error from handleCommand: " + strEx::itos(c));
263                        }
264                } catch(const NSPluginException& e) {
265                        LOG_ERROR_STD("Exception raised: " + e.error_ + " in module: " + e.file_);
266                }
267        }
268        // delete buffers
269        delete [] returnbuffer;
270        for (int i=0;i<len;i++) {
271                delete [] arguments[i];
272        }
273        delete [] arguments;
274        return ret;
275}
276/**
277 * Report a message to all logging enabled modules.
278 *
279 * @param msgType Message type
280 * @param file Filename generally __FILE__
281 * @param line  Line number, generaly __LINE__
282 * @param message The message as a human readable string.
283 */
284void NSClientT::reportMessage(int msgType, const char* file, const int line, std::string message) {
285        MutexLock lock(messageMutex);
286        pluginList::const_iterator plit;
287        for (plit = messageHandlers_.begin(); plit != messageHandlers_.end(); ++plit) {
288                try {
289                        (*plit)->handleMessage(msgType, file, line, message.c_str());
290                } catch(const NSPluginException& e) {
291                        // Here we are pretty much fucked! (as logging this might cause a loop :)
292                        throw "This shouldn't have happened...";
293                }
294        }
295}
296std::string NSClientT::getBasePath(void) {
297        if (!basePath.empty())
298                return basePath;
299        char* buffer = new char[1024];
300        GetModuleFileName(NULL, buffer, 1023);
301        std::string path = buffer;
302        std::string::size_type pos = path.rfind('\\');
303        basePath = path.substr(0, pos) + "\\";
304        delete [] buffer;
305        Settings::getInstance()->setFile(basePath + "NSC.ini");
306        return basePath;
307}
308
309
310int NSAPIGetSettingsString(const char* section, const char* key, const char* defaultValue, char* buffer, unsigned int bufLen) {
311        return NSCHelper::wrapReturnString(buffer, bufLen, Settings::getInstance()->getString(section, key, defaultValue));
312}
313int NSAPIGetSettingsInt(const char* section, const char* key, int defaultValue) {
314        return Settings::getInstance()->getInt(section, key, defaultValue);
315}
316
317
318int NSAPIGetBasePath(char*buffer, unsigned int bufLen) {
319        return NSCHelper::wrapReturnString(buffer, bufLen, mainClient.getBasePath());
320}
321int NSAPIGetApplicationName(char*buffer, unsigned int bufLen) {
322        return NSCHelper::wrapReturnString(buffer, bufLen, SZAPPNAME);
323}
324int NSAPIGetApplicationVersionStr(char*buffer, unsigned int bufLen) {
325        return NSCHelper::wrapReturnString(buffer, bufLen, SZVERSION);
326}
327void NSAPIMessage(int msgType, const char* file, const int line, const char* message) {
328        mainClient.reportMessage(msgType, file, line, message);
329}
330void NSAPIStopServer(void) {
331        serviceControll::Stop(SZSERVICENAME);
332}
333int NSAPIInject(const char* command, char* buffer, unsigned int bufLen) {
334        return NSCHelper::wrapReturnString(buffer, bufLen, mainClient.inject(command));
335}
336
337LPVOID NSAPILoader(char*buffer) {
338        if (stricmp(buffer, "NSAPIGetApplicationName") == 0)
339                return &NSAPIGetApplicationName;
340        if (stricmp(buffer, "NSAPIGetApplicationVersionStr") == 0)
341                return &NSAPIGetApplicationVersionStr;
342        if (stricmp(buffer, "NSAPIGetSettingsString") == 0)
343                return &NSAPIGetSettingsString;
344        if (stricmp(buffer, "NSAPIGetSettingsInt") == 0)
345                return &NSAPIGetSettingsInt;
346        if (stricmp(buffer, "NSAPIMessage") == 0)
347                return &NSAPIMessage;
348        if (stricmp(buffer, "NSAPIStopServer") == 0)
349                return &NSAPIStopServer;
350        if (stricmp(buffer, "NSAPIInject") == 0)
351                return &NSAPIInject;
352        if (stricmp(buffer, "NSAPIGetBasePath") == 0)
353                return &NSAPIGetBasePath;
354        return NULL;
355}
Note: See TracBrowser for help on using the repository browser.