source: nscp/include/client/command_line_parser.cpp @ a87ce04

0.4.00.4.10.4.2
Last change on this file since a87ce04 was a87ce04, checked in by Michael Medin <michael@…>, 17 months ago
  • Fixed some issues in the NRPE decoder
  • Added support for forwarding queries (ie. xxx_forward) mainly usefull for python(?) scripts where we can now handconstruct messages for delivery
  • Added NRPE unit tests (52 of them)
  • Fixed process enumeration API for 64/32 bit
  • Property mode set to 100644
File size: 12.0 KB
Line 
1#include <client/command_line_parser.hpp>
2#include <nscapi/functions.hpp>
3
4namespace po = boost::program_options;
5
6void client::command_line_parser::add_common_options(po::options_description &desc, data_type command_data) {
7        desc.add_options()
8                ("host,H", po::value<std::string>(&command_data->recipient.address), "The address of the host running the server")
9                ("timeout,T", po::value<int>(&command_data->timeout), "Number of seconds before connection times out (default=10)")
10                ("target,t", po::wvalue<std::wstring>(&command_data->target_id), "Target to use (lookup connection info from config)")
11                ("query,q", po::bool_switch(&command_data->query), "Force query mode (only useful when this is not already obvious)")
12                ("submit,s", po::bool_switch(&command_data->submit), "Force submit mode (only useful when this is not already obvious)")
13                ("exec,e", po::bool_switch(&command_data->exec), "Force exec mode (only useful when this is not already obvious)")
14                ;
15}
16void client::command_line_parser::add_query_options(po::options_description &desc, data_type command_data) {
17        desc.add_options()
18                ("command,c", po::wvalue<std::wstring>(&command_data->command), "The name of the query that the remote daemon should run")
19                ("arguments,a", po::wvalue<std::vector<std::wstring> >(&command_data->arguments), "list of arguments")
20                ("query-command", po::wvalue<std::wstring>(&command_data->command), "The name of the query that the remote daemon should run")
21                ("query-arguments", po::wvalue<std::vector<std::wstring> >(&command_data->arguments), "list of arguments")
22                ;
23}
24void client::command_line_parser::add_submit_options(po::options_description &desc, data_type command_data) {
25        desc.add_options()
26                ("command,c", po::wvalue<std::wstring>(&command_data->command), "The name of the command that the remote daemon should run")
27                ("message,m", po::wvalue<std::wstring>(&command_data->message), "Message")
28                ("result,r", po::value<unsigned int>(&command_data->result), "Result code")
29                ;
30}
31void client::command_line_parser::add_exec_options(po::options_description &desc, data_type command_data) {
32        desc.add_options()
33                ("command,c", po::wvalue<std::wstring>(&command_data->command), "The name of the command that the remote daemon should run")
34                ("arguments,a", po::wvalue<std::vector<std::wstring> >(&command_data->arguments), "list of arguments")
35                ;
36}
37
38std::wstring client::command_line_parser::build_help(configuration &config) {
39        po::options_description common("Common options");
40        add_common_options(common, config.data);
41        po::options_description query("Command: query");
42        add_query_options(query, config.data);
43        po::options_description submit("Command: submit");
44        add_submit_options(submit, config.data);
45        po::options_description exec("Command: exec");
46        add_exec_options(exec, config.data);
47        po::options_description desc("Options for the following commands: (query, submit, exec)");
48        desc.add(common).add(query).add(submit).add(config.local);
49        std::stringstream ss;
50        ss << desc;
51        return utf8::cvt<std::wstring>(ss.str());
52}
53
54
55int client::command_line_parser::do_execute_command_as_exec(configuration &config, const std::wstring &command, std::list<std::wstring> &arguments, std::string &result) {
56        if (!config.validate())
57                throw cli_exception("Invalid data: " + config.to_string());
58        if (command == _T("help")) {
59                return nscapi::functions::create_simple_exec_response_unknown(command, build_help(config), result);
60        } else if (command == _T("query")) {
61                std::wstring msg, perf;
62                int ret = do_query(config, command, arguments, result);
63                nscapi::functions::make_exec_from_query(result);
64                return ret;
65        } else if (command == _T("exec")) {
66                return do_exec(config, command, arguments, result);
67        } else if (command == _T("submit")) {
68                int ret = do_submit(config, command, arguments, result);
69                nscapi::functions::make_exec_from_submit(result);
70                return ret;
71        }
72        return NSCAPI::returnIgnored;
73}
74
75int client::command_line_parser::do_execute_command_as_query(configuration &config, const std::wstring &command, std::list<std::wstring> &arguments, const std::string &request, std::string &result) {
76        if (!config.validate())
77                throw cli_exception("Invalid data: " + config.to_string());
78        if (command == _T("help")) {
79                return nscapi::functions::create_simple_query_response_unknown(command, build_help(config), _T(""), result);
80        } else if (command == _T("query")) {
81                return do_query(config, command, arguments, result);
82        } else if (command == _T("forward")) {
83                return do_forward(config, request, result);
84        } else if (command == _T("exec")) {
85                int ret = do_exec(config, command, arguments, result);
86                nscapi::functions::make_query_from_exec(result);
87                return ret;
88        } else if (command == _T("submit")) {
89                int ret = do_submit(config, command, arguments, result);
90                nscapi::functions::make_query_from_submit(result);
91                return ret;
92        }
93        return NSCAPI::returnIgnored;
94}
95
96std::wstring client::command_manager::add_command(std::wstring name, std::wstring args) {
97        command_container data;
98        boost::escaped_list_separator<wchar_t> sep(L'\\', L' ', L'\"');
99        typedef boost::tokenizer<boost::escaped_list_separator<wchar_t>,std::wstring::const_iterator, std::wstring > tokenizer_t;
100        tokenizer_t tok(args, sep);
101        bool first = true;
102        BOOST_FOREACH(const std::wstring &s, tok) {
103                if (first) {
104                        data.command = s;
105                        first = false;
106                } else {
107                        data.arguments.push_back(s);
108                }
109        }
110
111        data.key = make_key(name);
112        commands[data.key] = data;
113        return data.key;
114}
115
116int client::command_manager::exec_simple(configuration &config, const std::wstring &target, const std::wstring &command, std::list<std::wstring> &arguments, std::string &response) {
117        command_type::const_iterator cit = commands.find(command);
118        if (cit == commands.end())
119                return NSCAPI::returnIgnored;
120        const command_container ci = (*cit).second;
121
122        std::list<std::wstring> rendered_arguments;
123        BOOST_FOREACH(std::wstring a, ci.arguments) {
124                int i=1;
125                BOOST_FOREACH(const std::wstring &param, arguments) {
126                        strEx::replace(a, _T("$ARG") + strEx::itos(i++)+_T("$"), param);
127                }
128                rendered_arguments.push_back(a);
129        }
130        // TODO: Add support for target here!
131        return client::command_line_parser::do_execute_command_as_exec(config, ci.command, rendered_arguments, response);
132}
133int client::command_line_parser::do_query(configuration &config, const std::wstring &command, std::list<std::wstring> &arguments, std::string &response) {
134        boost::program_options::variables_map vm;
135
136        po::options_description common("Common options");
137        add_common_options(common, config.data);
138        po::options_description query("Query NSCP options");
139        add_query_options(query, config.data);
140        po::options_description desc("Allowed options");
141        desc.add(common).add(query).add(config.local);
142
143        std::vector<std::wstring> vargs(arguments.begin(), arguments.end());
144        po::positional_options_description p;
145        p.add("arguments", -1);
146        po::wparsed_options parsed = po::basic_command_line_parser<wchar_t>(vargs).options(desc).positional(p).run();
147        po::store(parsed, vm);
148        po::notify(vm);
149        if (!config.data->target_id.empty()) {
150                if (!config.target_lookup)
151                        throw cli_exception("No target interface given when looking for targets");
152                config.data->recipient.import(config.target_lookup->lookup_target(config.data->target_id));
153        }
154
155        Plugin::QueryRequestMessage message;
156        nscapi::functions::create_simple_header(message.mutable_header());
157        modify_header(config, message.mutable_header(), config.data->recipient);
158        nscapi::functions::append_simple_query_request_payload(message.add_payload(), config.data->command, config.data->arguments);
159        return config.handler->query(config.data, message.mutable_header(), message.SerializeAsString(), response);
160}
161
162int client::command_line_parser::do_forward(configuration &config, const std::string &request, std::string &response) {
163        /*
164        if (!config.data->target_id.empty()) {
165                if (!config.target_lookup)
166                        throw cli_exception("No target interface given when looking for targets");
167                config.data->recipient.import(config.target_lookup->lookup_target(config.data->target_id));
168        }
169        */
170        Plugin::QueryRequestMessage message;
171        message.ParseFromString(request);
172        return config.handler->query(config.data, message.mutable_header(), request, response);
173}
174
175int client::command_line_parser::do_exec(configuration &config, const std::wstring &command, std::list<std::wstring> &arguments, std::string &result) {
176        boost::program_options::variables_map vm;
177
178        po::options_description common("Common options");
179        add_common_options(common, config.data);
180        po::options_description query("Query NSCP options");
181        add_exec_options(query, config.data);
182        po::options_description desc("Allowed options");
183        desc.add(common).add(query).add(config.local);
184
185        std::vector<std::wstring> vargs(arguments.begin(), arguments.end());
186        po::positional_options_description p;
187        p.add("arguments", -1);
188        po::wparsed_options parsed = po::basic_command_line_parser<wchar_t>(vargs).options(desc).positional(p).run();
189        po::store(parsed, vm);
190        po::notify(vm);
191        if (!config.data->target_id.empty()) {
192                if (!config.target_lookup)
193                        throw cli_exception("No target interface given when looking for targets");
194                config.data->recipient.import(config.target_lookup->lookup_target(config.data->target_id));
195        }
196
197        Plugin::ExecuteRequestMessage message;
198        nscapi::functions::create_simple_header(message.mutable_header());
199        modify_header(config, message.mutable_header(), config.data->recipient);
200        std::string response;
201        nscapi::functions::append_simple_exec_request_payload(message.add_payload(), config.data->command, config.data->arguments);
202        return config.handler->exec(config.data, message.mutable_header(), message.SerializeAsString(), response);
203}
204
205int client::command_line_parser::do_submit(configuration &config, const std::wstring &command, std::list<std::wstring> &arguments, std::string &result) {
206        boost::program_options::variables_map vm;
207        po::options_description common("Common options");
208        add_common_options(common, config.data);
209        po::options_description submit("Submit options");
210        add_submit_options(submit, config.data);
211        po::options_description desc("Allowed options");
212        desc.add(common).add(submit).add(config.local);
213
214        std::vector<std::wstring> vargs(arguments.begin(), arguments.end());
215        po::wparsed_options parsed = po::basic_command_line_parser<wchar_t>(vargs).options(desc).run();
216        po::store(parsed, vm);
217        po::notify(vm);
218        if (!config.data->target_id.empty()) {
219                if (!config.target_lookup)
220                        throw cli_exception("No target interface given when looking for targets");
221                config.data->recipient.import(config.target_lookup->lookup_target(config.data->target_id));
222        }
223
224        Plugin::SubmitRequestMessage message;
225        nscapi::functions::create_simple_header(message.mutable_header());
226        modify_header(config, message.mutable_header(), config.data->recipient);
227        message.set_channel("CLI");
228        nscapi::functions::append_simple_submit_request_payload(message.add_payload(), config.data->command, config.data->result, config.data->message);
229
230        return config.handler->submit(config.data, message.mutable_header(), message.SerializeAsString(), result);
231}
232void client::command_line_parser::modify_header(configuration &config, ::Plugin::Common_Header* header, nscapi::functions::destination_container &recipient) {
233        nscapi::functions::destination_container myself = config.data->host_self;
234        if (!header->has_recipient_id()) {
235                if (recipient.id.empty())
236                        recipient.id = "TODO missing id";
237                nscapi::functions::add_host(header, recipient);
238                header->set_recipient_id(recipient.id);
239        }
240        nscapi::functions::add_host(header, myself);
241        if (!header->has_source_id())
242                header->set_source_id(myself.id);
243        header->set_sender_id(myself.id);
244}
245
246int client::command_line_parser::do_relay_submit(configuration &config, const std::string &request, std::string &response) {
247        Plugin::SubmitRequestMessage message;
248        message.ParseFromString(request);
249        modify_header(config, message.mutable_header(), config.data->recipient);
250        return config.handler->submit(config.data, message.mutable_header(), message.SerializeAsString(), response);
251}
252
Note: See TracBrowser for help on using the repository browser.