summaryrefslogtreecommitdiffstats
path: root/plugins/check_by_ssh.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_by_ssh.c')
-rw-r--r--plugins/check_by_ssh.c720
1 files changed, 367 insertions, 353 deletions
diff --git a/plugins/check_by_ssh.c b/plugins/check_by_ssh.c
index 2a23b397..2bc38d49 100644
--- a/plugins/check_by_ssh.c
+++ b/plugins/check_by_ssh.c
@@ -1,495 +1,509 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_by_ssh plugin 3 * Monitoring check_by_ssh plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2008 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_by_ssh plugin 10 * This file contains the check_by_ssh plugin
11* 11 *
12* 12 *
13* This program is free software: you can redistribute it and/or modify 13 * This program is free software: you can redistribute it and/or modify
14* it under the terms of the GNU General Public License as published by 14 * it under the terms of the GNU General Public License as published by
15* the Free Software Foundation, either version 3 of the License, or 15 * the Free Software Foundation, either version 3 of the License, or
16* (at your option) any later version. 16 * (at your option) any later version.
17* 17 *
18* This program is distributed in the hope that it will be useful, 18 * This program is distributed in the hope that it will be useful,
19* but WITHOUT ANY WARRANTY; without even the implied warranty of 19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21* GNU General Public License for more details. 21 * GNU General Public License for more details.
22* 22 *
23* You should have received a copy of the GNU General Public License 23 * You should have received a copy of the GNU General Public License
24* along with this program. If not, see <http://www.gnu.org/licenses/>. 24 * along with this program. If not, see <http://www.gnu.org/licenses/>.
25* 25 *
26* 26 *
27*****************************************************************************/ 27 *****************************************************************************/
28 28
29const char *progname = "check_by_ssh"; 29const char *progname = "check_by_ssh";
30const char *copyright = "2000-2008"; 30const char *copyright = "2000-2024";
31const char *email = "devel@monitoring-plugins.org"; 31const char *email = "devel@monitoring-plugins.org";
32 32
33#include "common.h" 33#include "common.h"
34#include "utils.h" 34#include "utils.h"
35#include "netutils.h"
36#include "utils_cmd.h" 35#include "utils_cmd.h"
36#include "check_by_ssh.d/config.h"
37#include "states.h"
37 38
38#ifndef NP_MAXARGS 39#ifndef NP_MAXARGS
39#define NP_MAXARGS 1024 40# define NP_MAXARGS 1024
40#endif 41#endif
41 42
42int process_arguments (int, char **); 43typedef struct {
43int validate_arguments (void); 44 int errorcode;
44void comm_append (const char *); 45 check_by_ssh_config config;
45void print_help (void); 46} check_by_ssh_config_wrapper;
46void print_usage (void); 47static check_by_ssh_config_wrapper process_arguments(int /*argc*/, char ** /*argv*/);
47 48static check_by_ssh_config_wrapper validate_arguments(check_by_ssh_config_wrapper /*config_wrapper*/);
48unsigned int commands = 0;
49unsigned int services = 0;
50int skip_stdout = 0;
51int skip_stderr = 0;
52int warn_on_stderr = 0;
53bool unknown_timeout = false;
54char *remotecmd = NULL;
55char **commargv = NULL;
56int commargc = 0;
57char *hostname = NULL;
58char *outputfile = NULL;
59char *host_shortname = NULL;
60char **service;
61bool passive = false;
62bool verbose = false;
63
64int
65main (int argc, char **argv)
66{
67 49
68 char *status_text; 50static command_construct comm_append(command_construct /*cmd*/, const char * /*str*/);
69 int cresult; 51static void print_help(void);
70 int result = STATE_UNKNOWN; 52void print_usage(void);
71 time_t local_time;
72 FILE *fp = NULL;
73 output chld_out, chld_err;
74 53
75 remotecmd = ""; 54static bool verbose = false;
76 comm_append(SSH_COMMAND);
77 55
78 setlocale (LC_ALL, ""); 56int main(int argc, char **argv) {
79 bindtextdomain (PACKAGE, LOCALEDIR); 57 setlocale(LC_ALL, "");
80 textdomain (PACKAGE); 58 bindtextdomain(PACKAGE, LOCALEDIR);
59 textdomain(PACKAGE);
81 60
82 /* Parse extra opts if any */ 61 /* Parse extra opts if any */
83 argv=np_extra_opts (&argc, argv, progname); 62 argv = np_extra_opts(&argc, argv, progname);
63
64 check_by_ssh_config_wrapper tmp_config = process_arguments(argc, argv);
84 65
85 /* process arguments */ 66 /* process arguments */
86 if (process_arguments (argc, argv) == ERROR) 67 if (tmp_config.errorcode == ERROR) {
87 usage_va(_("Could not parse arguments")); 68 usage_va(_("Could not parse arguments"));
69 }
70
71 const check_by_ssh_config config = tmp_config.config;
88 72
89 /* Set signal handling and alarm timeout */ 73 /* Set signal handling and alarm timeout */
90 if (signal (SIGALRM, timeout_alarm_handler) == SIG_ERR) { 74 if (signal(SIGALRM, timeout_alarm_handler) == SIG_ERR) {
91 usage_va(_("Cannot catch SIGALRM")); 75 usage_va(_("Cannot catch SIGALRM"));
92 } 76 }
93 alarm (timeout_interval); 77 alarm(timeout_interval);
94 78
95 /* run the command */ 79 /* run the command */
96 if (verbose) { 80 if (verbose) {
97 printf ("Command: %s\n", commargv[0]); 81 printf("Command: %s\n", config.cmd.commargv[0]);
98 for (int i = 1; i < commargc; i++) 82 for (int i = 1; i < config.cmd.commargc; i++) {
99 printf ("Argument %i: %s\n", i, commargv[i]); 83 printf("Argument %i: %s\n", i, config.cmd.commargv[i]);
84 }
100 } 85 }
101 86
102 result = cmd_run_array (commargv, &chld_out, &chld_err, 0); 87 output chld_out;
88 output chld_err;
89 mp_state_enum result = cmd_run_array(config.cmd.commargv, &chld_out, &chld_err, 0);
103 90
104 /* SSH returns 255 if connection attempt fails; include the first line of error output */ 91 /* SSH returns 255 if connection attempt fails; include the first line of error output */
105 if (result == 255 && unknown_timeout) { 92 if (result == 255 && config.unknown_timeout) {
106 printf (_("SSH connection failed: %s\n"), 93 printf(_("SSH connection failed: %s\n"), chld_err.lines > 0 ? chld_err.line[0] : "(no error output)");
107 chld_err.lines > 0 ? chld_err.line[0] : "(no error output)");
108 return STATE_UNKNOWN; 94 return STATE_UNKNOWN;
109 } 95 }
110 96
111 if (verbose) { 97 if (verbose) {
112 for(size_t i = 0; i < chld_out.lines; i++) 98 for (size_t i = 0; i < chld_out.lines; i++) {
113 printf("stdout: %s\n", chld_out.line[i]); 99 printf("stdout: %s\n", chld_out.line[i]);
114 for(size_t i = 0; i < chld_err.lines; i++) 100 }
101 for (size_t i = 0; i < chld_err.lines; i++) {
115 printf("stderr: %s\n", chld_err.line[i]); 102 printf("stderr: %s\n", chld_err.line[i]);
103 }
116 } 104 }
117 105
118 if (skip_stdout == -1) /* --skip-stdout specified without argument */ 106 size_t skip_stdout = 0;
107 if (config.skip_stdout == -1) { /* --skip-stdout specified without argument */
119 skip_stdout = chld_out.lines; 108 skip_stdout = chld_out.lines;
120 if (skip_stderr == -1) /* --skip-stderr specified without argument */ 109 } else {
110 skip_stdout = config.skip_stdout;
111 }
112
113 size_t skip_stderr = 0;
114 if (config.skip_stderr == -1) { /* --skip-stderr specified without argument */
121 skip_stderr = chld_err.lines; 115 skip_stderr = chld_err.lines;
116 } else {
117 skip_stderr = config.skip_stderr;
118 }
122 119
123 /* UNKNOWN or worse if (non-skipped) output found on stderr */ 120 /* UNKNOWN or worse if (non-skipped) output found on stderr */
124 if(chld_err.lines > (size_t)skip_stderr) { 121 if (chld_err.lines > (size_t)skip_stderr) {
125 printf (_("Remote command execution failed: %s\n"), 122 printf(_("Remote command execution failed: %s\n"), chld_err.line[skip_stderr]);
126 chld_err.line[skip_stderr]); 123 if (config.warn_on_stderr) {
127 if ( warn_on_stderr )
128 return max_state_alt(result, STATE_WARNING); 124 return max_state_alt(result, STATE_WARNING);
129 else 125 }
130 return max_state_alt(result, STATE_UNKNOWN); 126 return max_state_alt(result, STATE_UNKNOWN);
131 } 127 }
132 128
133 /* this is simple if we're not supposed to be passive. 129 /* this is simple if we're not supposed to be passive.
134 * Wrap up quickly and keep the tricks below */ 130 * Wrap up quickly and keep the tricks below */
135 if(!passive) { 131 if (!config.passive) {
136 if (chld_out.lines > (size_t)skip_stdout) 132 if (chld_out.lines > (size_t)skip_stdout) {
137 for (size_t i = skip_stdout; i < chld_out.lines; i++) 133 for (size_t i = skip_stdout; i < chld_out.lines; i++) {
138 puts (chld_out.line[i]); 134 puts(chld_out.line[i]);
139 else 135 }
140 printf (_("%s - check_by_ssh: Remote command '%s' returned status %d\n"), 136 } else {
141 state_text(result), remotecmd, result); 137 printf(_("%s - check_by_ssh: Remote command '%s' returned status %d\n"), state_text(result), config.remotecmd, result);
142 return result; /* return error status from remote command */ 138 }
139 return result; /* return error status from remote command */
143 } 140 }
144 141
145
146 /* 142 /*
147 * Passive mode 143 * Passive mode
148 */ 144 */
149 145
150 /* process output */ 146 /* process output */
151 if (!(fp = fopen (outputfile, "a"))) { 147 FILE *file_pointer = NULL;
152 printf (_("SSH WARNING: could not open %s\n"), outputfile); 148 if (!(file_pointer = fopen(config.outputfile, "a"))) {
153 exit (STATE_UNKNOWN); 149 printf(_("SSH WARNING: could not open %s\n"), config.outputfile);
150 exit(STATE_UNKNOWN);
154 } 151 }
155 152
156 local_time = time (NULL); 153 time_t local_time = time(NULL);
157 commands = 0; 154 unsigned int commands = 0;
158 for(size_t i = skip_stdout; i < chld_out.lines; i++) { 155 char *status_text;
156 int cresult;
157 for (size_t i = skip_stdout; i < chld_out.lines; i++) {
159 status_text = chld_out.line[i++]; 158 status_text = chld_out.line[i++];
160 if (i == chld_out.lines || strstr (chld_out.line[i], "STATUS CODE: ") == NULL) 159 if (i == chld_out.lines || strstr(chld_out.line[i], "STATUS CODE: ") == NULL) {
161 die (STATE_UNKNOWN, _("%s: Error parsing output\n"), progname); 160 die(STATE_UNKNOWN, _("%s: Error parsing output\n"), progname);
162 161 }
163 if (service[commands] && status_text 162
164 && sscanf (chld_out.line[i], "STATUS CODE: %d", &cresult) == 1) 163 if (config.service[commands] && status_text && sscanf(chld_out.line[i], "STATUS CODE: %d", &cresult) == 1) {
165 { 164 fprintf(file_pointer, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", (int)local_time, config.host_shortname,
166 fprintf (fp, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n", 165 config.service[commands++], cresult, status_text);
167 (int) local_time, host_shortname, service[commands++],
168 cresult, status_text);
169 } 166 }
170 } 167 }
171 168
172 /* Multiple commands and passive checking should always return OK */ 169 /* Multiple commands and passive checking should always return OK */
173 return result; 170 exit(result);
174} 171}
175 172
176/* process command-line arguments */ 173/* process command-line arguments */
177int 174check_by_ssh_config_wrapper process_arguments(int argc, char **argv) {
178process_arguments (int argc, char **argv) 175 static struct option longopts[] = {{"version", no_argument, 0, 'V'},
179{ 176 {"help", no_argument, 0, 'h'},
180 int c; 177 {"verbose", no_argument, 0, 'v'},
181 char *p1, *p2; 178 {"fork", no_argument, 0, 'f'},
182 179 {"timeout", required_argument, 0, 't'},
183 int option = 0; 180 {"unknown-timeout", no_argument, 0, 'U'},
184 static struct option longopts[] = { 181 {"host", required_argument, 0, 'H'}, /* backward compatibility */
185 {"version", no_argument, 0, 'V'}, 182 {"hostname", required_argument, 0, 'H'},
186 {"help", no_argument, 0, 'h'}, 183 {"port", required_argument, 0, 'p'},
187 {"verbose", no_argument, 0, 'v'}, 184 {"output", required_argument, 0, 'O'},
188 {"fork", no_argument, 0, 'f'}, 185 {"name", required_argument, 0, 'n'},
189 {"timeout", required_argument, 0, 't'}, 186 {"services", required_argument, 0, 's'},
190 {"unknown-timeout", no_argument, 0, 'U'}, 187 {"identity", required_argument, 0, 'i'},
191 {"host", required_argument, 0, 'H'}, /* backward compatibility */ 188 {"user", required_argument, 0, 'u'},
192 {"hostname", required_argument, 0, 'H'}, 189 {"logname", required_argument, 0, 'l'},
193 {"port", required_argument,0,'p'}, 190 {"command", required_argument, 0, 'C'},
194 {"output", required_argument, 0, 'O'}, 191 {"skip", optional_argument, 0, 'S'}, /* backwards compatibility */
195 {"name", required_argument, 0, 'n'}, 192 {"skip-stdout", optional_argument, 0, 'S'},
196 {"services", required_argument, 0, 's'}, 193 {"skip-stderr", optional_argument, 0, 'E'},
197 {"identity", required_argument, 0, 'i'}, 194 {"warn-on-stderr", no_argument, 0, 'W'},
198 {"user", required_argument, 0, 'u'}, 195 {"proto1", no_argument, 0, '1'},
199 {"logname", required_argument, 0, 'l'}, 196 {"proto2", no_argument, 0, '2'},
200 {"command", required_argument, 0, 'C'}, 197 {"use-ipv4", no_argument, 0, '4'},
201 {"skip", optional_argument, 0, 'S'}, /* backwards compatibility */ 198 {"use-ipv6", no_argument, 0, '6'},
202 {"skip-stdout", optional_argument, 0, 'S'}, 199 {"ssh-option", required_argument, 0, 'o'},
203 {"skip-stderr", optional_argument, 0, 'E'}, 200 {"quiet", no_argument, 0, 'q'},
204 {"warn-on-stderr", no_argument, 0, 'W'}, 201 {"configfile", optional_argument, 0, 'F'},
205 {"proto1", no_argument, 0, '1'}, 202 {0, 0, 0, 0}};
206 {"proto2", no_argument, 0, '2'}, 203
207 {"use-ipv4", no_argument, 0, '4'}, 204 check_by_ssh_config_wrapper result = {
208 {"use-ipv6", no_argument, 0, '6'}, 205 .errorcode = OK,
209 {"ssh-option", required_argument, 0, 'o'}, 206 .config = check_by_ssh_config_init(),
210 {"quiet", no_argument, 0, 'q'},
211 {"configfile", optional_argument, 0, 'F'},
212 {0, 0, 0, 0}
213 }; 207 };
214 208
215 if (argc < 2) 209 if (argc < 2) {
216 return ERROR; 210 result.errorcode = ERROR;
211 return result;
212 }
213
214 for (int index = 1; index < argc; index++) {
215 if (strcmp("-to", argv[index]) == 0) {
216 strcpy(argv[index], "-t");
217 }
218 }
217 219
218 for (c = 1; c < argc; c++) 220 result.config.cmd = comm_append(result.config.cmd, SSH_COMMAND);
219 if (strcmp ("-to", argv[c]) == 0)
220 strcpy (argv[c], "-t");
221 221
222 while (1) { 222 int option = 0;
223 c = getopt_long (argc, argv, "Vvh1246fqt:UH:O:p:i:u:l:C:S::E::n:s:o:F:", longopts, 223 while (true) {
224 &option); 224 int opt_index = getopt_long(argc, argv, "Vvh1246fqt:UH:O:p:i:u:l:C:S::E::n:s:o:F:", longopts, &option);
225 225
226 if (c == -1 || c == EOF) 226 if (opt_index == -1 || opt_index == EOF) {
227 break; 227 break;
228 }
228 229
229 switch (c) { 230 switch (opt_index) {
230 case 'V': /* version */ 231 case 'V': /* version */
231 print_revision (progname, NP_VERSION); 232 print_revision(progname, NP_VERSION);
232 exit (STATE_UNKNOWN); 233 exit(STATE_UNKNOWN);
233 case 'h': /* help */ 234 case 'h': /* help */
234 print_help (); 235 print_help();
235 exit (STATE_UNKNOWN); 236 exit(STATE_UNKNOWN);
236 case 'v': /* help */ 237 case 'v': /* help */
237 verbose = true; 238 verbose = true;
238 break; 239 break;
239 case 't': /* timeout period */ 240 case 't': /* timeout period */
240 if (!is_integer (optarg)) 241 if (!is_integer(optarg)) {
241 usage_va(_("Timeout interval must be a positive integer")); 242 usage_va(_("Timeout interval must be a positive integer"));
242 else 243 } else {
243 timeout_interval = atoi (optarg); 244 timeout_interval = atoi(optarg);
245 }
244 break; 246 break;
245 case 'U': 247 case 'U':
246 unknown_timeout = true; 248 result.config.unknown_timeout = true;
247 break; 249 break;
248 case 'H': /* host */ 250 case 'H': /* host */
249 hostname = optarg; 251 result.config.hostname = optarg;
250 break; 252 break;
251 case 'p': /* port number */ 253 case 'p': /* port number */
252 if (!is_integer (optarg)) 254 if (!is_integer(optarg)) {
253 usage_va(_("Port must be a positive integer")); 255 usage_va(_("Port must be a positive integer"));
254 comm_append("-p"); 256 }
255 comm_append(optarg); 257 result.config.cmd = comm_append(result.config.cmd, "-p");
258 result.config.cmd = comm_append(result.config.cmd, optarg);
256 break; 259 break;
257 case 'O': /* output file */ 260 case 'O': /* output file */
258 outputfile = optarg; 261 result.config.outputfile = optarg;
259 passive = true; 262 result.config.passive = true;
260 break; 263 break;
261 case 's': /* description of service to check */ 264 case 's': /* description of service to check */ {
265 char *p1;
266 char *p2;
267
262 p1 = optarg; 268 p1 = optarg;
263 service = realloc (service, (++services) * sizeof(char *)); 269 result.config.service = realloc(result.config.service, (++result.config.number_of_services) * sizeof(char *));
264 while ((p2 = index (p1, ':'))) { 270 while ((p2 = index(p1, ':'))) {
265 *p2 = '\0'; 271 *p2 = '\0';
266 service[services - 1] = p1; 272 result.config.service[result.config.number_of_services - 1] = p1;
267 service = realloc (service, (++services) * sizeof(char *)); 273 result.config.service = realloc(result.config.service, (++result.config.number_of_services) * sizeof(char *));
268 p1 = p2 + 1; 274 p1 = p2 + 1;
269 } 275 }
270 service[services - 1] = p1; 276 result.config.service[result.config.number_of_services - 1] = p1;
271 break; 277 break;
272 case 'n': /* short name of host in the monitoring configuration */ 278 case 'n': /* short name of host in the monitoring configuration */
273 host_shortname = optarg; 279 result.config.host_shortname = optarg;
274 break; 280 } break;
275
276 case 'u': 281 case 'u':
277 comm_append("-l"); 282 result.config.cmd = comm_append(result.config.cmd, "-l");
278 comm_append(optarg); 283 result.config.cmd = comm_append(result.config.cmd, optarg);
279 break; 284 break;
280 case 'l': /* login name */ 285 case 'l': /* login name */
281 comm_append("-l"); 286 result.config.cmd = comm_append(result.config.cmd, "-l");
282 comm_append(optarg); 287 result.config.cmd = comm_append(result.config.cmd, optarg);
283 break; 288 break;
284 case 'i': /* identity */ 289 case 'i': /* identity */
285 comm_append("-i"); 290 result.config.cmd = comm_append(result.config.cmd, "-i");
286 comm_append(optarg); 291 result.config.cmd = comm_append(result.config.cmd, optarg);
287 break; 292 break;
288 293
289 case '1': /* Pass these switches directly to ssh */ 294 case '1': /* Pass these switches directly to ssh */
290 comm_append("-1"); 295 result.config.cmd = comm_append(result.config.cmd, "-1");
291 break; 296 break;
292 case '2': /* 1 to force version 1, 2 to force version 2 */ 297 case '2': /* 1 to force version 1, 2 to force version 2 */
293 comm_append("-2"); 298 result.config.cmd = comm_append(result.config.cmd, "-2");
294 break; 299 break;
295 case '4': /* -4 for IPv4 */ 300 case '4': /* -4 for IPv4 */
296 comm_append("-4"); 301 result.config.cmd = comm_append(result.config.cmd, "-4");
297 break; 302 break;
298 case '6': /* -6 for IPv6 */ 303 case '6': /* -6 for IPv6 */
299 comm_append("-6"); 304 result.config.cmd = comm_append(result.config.cmd, "-6");
300 break; 305 break;
301 case 'f': /* fork to background */ 306 case 'f': /* fork to background */
302 comm_append("-f"); 307 result.config.cmd = comm_append(result.config.cmd, "-f");
303 break; 308 break;
304 case 'C': /* Command for remote machine */ 309 case 'C': /* Command for remote machine */
305 commands++; 310 result.config.commands++;
306 if (commands > 1) 311 if (result.config.commands > 1) {
307 xasprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd); 312 xasprintf(&result.config.remotecmd, "%s;echo STATUS CODE: $?;", result.config.remotecmd);
308 xasprintf (&remotecmd, "%s%s", remotecmd, optarg); 313 }
314 xasprintf(&result.config.remotecmd, "%s%s", result.config.remotecmd, optarg);
309 break; 315 break;
310 case 'S': /* skip n (or all) lines on stdout */ 316 case 'S': /* skip n (or all) lines on stdout */
311 if (optarg == NULL) 317 if (optarg == NULL) {
312 skip_stdout = -1; /* skip all output on stdout */ 318 result.config.skip_stdout = -1; /* skip all output on stdout */
313 else if (!is_integer (optarg)) 319 } else if (!is_integer(optarg)) {
314 usage_va(_("skip-stdout argument must be an integer")); 320 usage_va(_("skip-stdout argument must be an integer"));
315 else 321 } else {
316 skip_stdout = atoi (optarg); 322 result.config.skip_stdout = atoi(optarg);
323 }
317 break; 324 break;
318 case 'E': /* skip n (or all) lines on stderr */ 325 case 'E': /* skip n (or all) lines on stderr */
319 if (optarg == NULL) 326 if (optarg == NULL) {
320 skip_stderr = -1; /* skip all output on stderr */ 327 result.config.skip_stderr = -1; /* skip all output on stderr */
321 else if (!is_integer (optarg)) 328 } else if (!is_integer(optarg)) {
322 usage_va(_("skip-stderr argument must be an integer")); 329 usage_va(_("skip-stderr argument must be an integer"));
323 else 330 } else {
324 skip_stderr = atoi (optarg); 331 result.config.skip_stderr = atoi(optarg);
332 }
325 break; 333 break;
326 case 'W': /* exit with warning if there is an output on stderr */ 334 case 'W': /* exit with warning if there is an output on stderr */
327 warn_on_stderr = 1; 335 result.config.warn_on_stderr = true;
328 break; 336 break;
329 case 'o': /* Extra options for the ssh command */ 337 case 'o': /* Extra options for the ssh command */
330 comm_append("-o"); 338 result.config.cmd = comm_append(result.config.cmd, "-o");
331 comm_append(optarg); 339 result.config.cmd = comm_append(result.config.cmd, optarg);
332 break; 340 break;
333 case 'q': /* Tell the ssh command to be quiet */ 341 case 'q': /* Tell the ssh command to be quiet */
334 comm_append("-q"); 342 result.config.cmd = comm_append(result.config.cmd, "-q");
335 break; 343 break;
336 case 'F': /* ssh configfile */ 344 case 'F': /* ssh configfile */
337 comm_append("-F"); 345 result.config.cmd = comm_append(result.config.cmd, "-F");
338 comm_append(optarg); 346 result.config.cmd = comm_append(result.config.cmd, optarg);
339 break; 347 break;
340 default: /* help */ 348 default: /* help */
341 usage5(); 349 usage5();
342 } 350 }
343 } 351 }
344 352
345 c = optind; 353 int c = optind;
346 if (hostname == NULL) { 354 if (result.config.hostname == NULL) {
347 if (c <= argc) { 355 if (c <= argc) {
348 die (STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname); 356 die(STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname);
349 } 357 }
350 hostname = argv[c++]; 358 result.config.hostname = argv[c++];
351 } 359 }
352 360
353 if (strlen(remotecmd) == 0) { 361 if (strlen(result.config.remotecmd) == 0) {
354 for (; c < argc; c++) 362 for (; c < argc; c++) {
355 if (strlen(remotecmd) > 0) 363 if (strlen(result.config.remotecmd) > 0) {
356 xasprintf (&remotecmd, "%s %s", remotecmd, argv[c]); 364 xasprintf(&result.config.remotecmd, "%s %s", result.config.remotecmd, argv[c]);
357 else 365 } else {
358 xasprintf (&remotecmd, "%s", argv[c]); 366 xasprintf(&result.config.remotecmd, "%s", argv[c]);
367 }
368 }
359 } 369 }
360 370
361 if (commands > 1 || passive) 371 if (result.config.commands > 1 || result.config.passive) {
362 xasprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd); 372 xasprintf(&result.config.remotecmd, "%s;echo STATUS CODE: $?;", result.config.remotecmd);
373 }
363 374
364 if (remotecmd == NULL || strlen (remotecmd) <= 1) 375 if (result.config.remotecmd == NULL || strlen(result.config.remotecmd) <= 1) {
365 usage_va(_("No remotecmd")); 376 usage_va(_("No remotecmd"));
377 }
366 378
367 comm_append(hostname); 379 result.config.cmd = comm_append(result.config.cmd, result.config.hostname);
368 comm_append(remotecmd); 380 result.config.cmd = comm_append(result.config.cmd, result.config.remotecmd);
369 381
370 return validate_arguments (); 382 return validate_arguments(result);
371} 383}
372 384
385command_construct comm_append(command_construct cmd, const char *str) {
373 386
374void 387 if (verbose) {
375comm_append (const char *str) 388 for (int i = 0; i < cmd.commargc; i++) {
376{ 389 printf("Current command: [%i] %s\n", i, cmd.commargv[i]);
390 }
391
392 printf("Appending: %s\n", str);
393 }
377 394
378 if (++commargc > NP_MAXARGS) 395 if (++cmd.commargc > NP_MAXARGS) {
379 die(STATE_UNKNOWN, _("%s: Argument limit of %d exceeded\n"), progname, NP_MAXARGS); 396 die(STATE_UNKNOWN, _("%s: Argument limit of %d exceeded\n"), progname, NP_MAXARGS);
397 }
380 398
381 if ((commargv = (char **)realloc(commargv, (commargc+1) * sizeof(char *))) == NULL) 399 if ((cmd.commargv = (char **)realloc(cmd.commargv, (cmd.commargc + 1) * sizeof(char *))) == NULL) {
382 die(STATE_UNKNOWN, _("Can not (re)allocate 'commargv' buffer\n")); 400 die(STATE_UNKNOWN, _("Can not (re)allocate 'commargv' buffer\n"));
401 }
383 402
384 commargv[commargc-1] = strdup(str); 403 cmd.commargv[cmd.commargc - 1] = strdup(str);
385 commargv[commargc] = NULL; 404 cmd.commargv[cmd.commargc] = NULL;
386 405
406 return cmd;
387} 407}
388 408
389int 409check_by_ssh_config_wrapper validate_arguments(check_by_ssh_config_wrapper config_wrapper) {
390validate_arguments (void) 410 if (config_wrapper.config.remotecmd == NULL || config_wrapper.config.hostname == NULL) {
391{ 411 config_wrapper.errorcode = ERROR;
392 if (remotecmd == NULL || hostname == NULL) 412 return config_wrapper;
393 return ERROR; 413 }
394 414
395 if (passive && commands != services) 415 if (config_wrapper.config.passive && config_wrapper.config.commands != config_wrapper.config.number_of_services) {
396 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname); 416 die(STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname);
417 }
397 418
398 if (passive && host_shortname == NULL) 419 if (config_wrapper.config.passive && config_wrapper.config.host_shortname == NULL) {
399 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the monitoring configs.\n"), progname); 420 die(STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the monitoring configs.\n"), progname);
421 }
400 422
401 return OK; 423 return config_wrapper;
402} 424}
403 425
404 426void print_help(void) {
405void 427 print_revision(progname, NP_VERSION);
406print_help (void) 428
407{ 429 printf("Copyright (c) 1999 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
408 print_revision (progname, NP_VERSION); 430 printf(COPYRIGHT, copyright, email);
409 431
410 printf ("Copyright (c) 1999 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n"); 432 printf(_("This plugin uses SSH to execute commands on a remote host"));
411 printf (COPYRIGHT, copyright, email); 433
412 434 printf("\n\n");
413 printf (_("This plugin uses SSH to execute commands on a remote host")); 435
414 436 print_usage();
415 printf ("\n\n"); 437
416 438 printf(UT_HELP_VRSN);
417 print_usage (); 439
418 440 printf(UT_EXTRA_OPTS);
419 printf (UT_HELP_VRSN); 441
420 442 printf(UT_HOST_PORT, 'p', "none");
421 printf (UT_EXTRA_OPTS); 443
422 444 printf(UT_IPv46);
423 printf (UT_HOST_PORT, 'p', "none"); 445
424 446 printf(" %s\n", "-1, --proto1");
425 printf (UT_IPv46); 447 printf(" %s\n", _("tell ssh to use Protocol 1 [optional]"));
426 448 printf(" %s\n", "-2, --proto2");
427 printf (" %s\n", "-1, --proto1"); 449 printf(" %s\n", _("tell ssh to use Protocol 2 [optional]"));
428 printf (" %s\n", _("tell ssh to use Protocol 1 [optional]")); 450 printf(" %s\n", "-S, --skip-stdout[=n]");
429 printf (" %s\n", "-2, --proto2"); 451 printf(" %s\n", _("Ignore all or (if specified) first n lines on STDOUT [optional]"));
430 printf (" %s\n", _("tell ssh to use Protocol 2 [optional]")); 452 printf(" %s\n", "-E, --skip-stderr[=n]");
431 printf (" %s\n", "-S, --skip-stdout[=n]"); 453 printf(" %s\n", _("Ignore all or (if specified) first n lines on STDERR [optional]"));
432 printf (" %s\n", _("Ignore all or (if specified) first n lines on STDOUT [optional]")); 454 printf(" %s\n", "-W, --warn-on-stderr]");
433 printf (" %s\n", "-E, --skip-stderr[=n]"); 455 printf(" %s\n", _("Exit with an warning, if there is an output on STDERR"));
434 printf (" %s\n", _("Ignore all or (if specified) first n lines on STDERR [optional]")); 456 printf(" %s\n", "-f");
435 printf (" %s\n", "-W, --warn-on-stderr]"); 457 printf(" %s\n", _("tells ssh to fork rather than create a tty [optional]. This will always return OK if ssh is executed"));
436 printf (" %s\n", _("Exit with an warning, if there is an output on STDERR")); 458 printf(" %s\n", "-C, --command='COMMAND STRING'");
437 printf (" %s\n", "-f"); 459 printf(" %s\n", _("command to execute on the remote machine"));
438 printf (" %s\n", _("tells ssh to fork rather than create a tty [optional]. This will always return OK if ssh is executed")); 460 printf(" %s\n", "-l, --logname=USERNAME");
439 printf (" %s\n","-C, --command='COMMAND STRING'"); 461 printf(" %s\n", _("SSH user name on remote host [optional]"));
440 printf (" %s\n", _("command to execute on the remote machine")); 462 printf(" %s\n", "-i, --identity=KEYFILE");
441 printf (" %s\n","-l, --logname=USERNAME"); 463 printf(" %s\n", _("identity of an authorized key [optional]"));
442 printf (" %s\n", _("SSH user name on remote host [optional]")); 464 printf(" %s\n", "-O, --output=FILE");
443 printf (" %s\n","-i, --identity=KEYFILE"); 465 printf(" %s\n", _("external command file for monitoring [optional]"));
444 printf (" %s\n", _("identity of an authorized key [optional]")); 466 printf(" %s\n", "-s, --services=LIST");
445 printf (" %s\n","-O, --output=FILE"); 467 printf(" %s\n", _("list of monitoring service names, separated by ':' [optional]"));
446 printf (" %s\n", _("external command file for monitoring [optional]")); 468 printf(" %s\n", "-n, --name=NAME");
447 printf (" %s\n","-s, --services=LIST"); 469 printf(" %s\n", _("short name of host in the monitoring configuration [optional]"));
448 printf (" %s\n", _("list of monitoring service names, separated by ':' [optional]")); 470 printf(" %s\n", "-o, --ssh-option=OPTION");
449 printf (" %s\n","-n, --name=NAME"); 471 printf(" %s\n", _("Call ssh with '-o OPTION' (may be used multiple times) [optional]"));
450 printf (" %s\n", _("short name of host in the monitoring configuration [optional]")); 472 printf(" %s\n", "-F, --configfile");
451 printf (" %s\n","-o, --ssh-option=OPTION"); 473 printf(" %s\n", _("Tell ssh to use this configfile [optional]"));
452 printf (" %s\n", _("Call ssh with '-o OPTION' (may be used multiple times) [optional]")); 474 printf(" %s\n", "-q, --quiet");
453 printf (" %s\n","-F, --configfile"); 475 printf(" %s\n", _("Tell ssh to suppress warning and diagnostic messages [optional]"));
454 printf (" %s\n", _("Tell ssh to use this configfile [optional]")); 476 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
455 printf (" %s\n","-q, --quiet"); 477 printf(" %s\n", "-U, --unknown-timeout");
456 printf (" %s\n", _("Tell ssh to suppress warning and diagnostic messages [optional]")); 478 printf(" %s\n", _("Make connection problems return UNKNOWN instead of CRITICAL"));
457 printf (UT_WARN_CRIT); 479 printf(UT_VERBOSE);
458 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 480 printf("\n");
459 printf (" %s\n","-U, --unknown-timeout"); 481 printf(" %s\n", _("The most common mode of use is to refer to a local identity file with"));
460 printf (" %s\n", _("Make connection problems return UNKNOWN instead of CRITICAL")); 482 printf(" %s\n", _("the '-i' option. In this mode, the identity pair should have a null"));
461 printf (UT_VERBOSE); 483 printf(" %s\n", _("passphrase and the public key should be listed in the authorized_keys"));
484 printf(" %s\n", _("file of the remote host. Usually the key will be restricted to running"));
485 printf(" %s\n", _("only one command on the remote server. If the remote SSH server tracks"));
486 printf(" %s\n", _("invocation arguments, the one remote program may be an agent that can"));
487 printf(" %s\n", _("execute additional commands as proxy"));
462 printf("\n"); 488 printf("\n");
463 printf (" %s\n", _("The most common mode of use is to refer to a local identity file with")); 489 printf(" %s\n", _("To use passive mode, provide multiple '-C' options, and provide"));
464 printf (" %s\n", _("the '-i' option. In this mode, the identity pair should have a null")); 490 printf(" %s\n", _("all of -O, -s, and -n options (servicelist order must match '-C'options)"));
465 printf (" %s\n", _("passphrase and the public key should be listed in the authorized_keys")); 491 printf("\n");
466 printf (" %s\n", _("file of the remote host. Usually the key will be restricted to running")); 492 printf("%s\n", _("Examples:"));
467 printf (" %s\n", _("only one command on the remote server. If the remote SSH server tracks")); 493 printf(" %s\n", "$ check_by_ssh -H localhost -n lh -s c1:c2:c3 -C uptime -C uptime -C uptime -O /tmp/foo");
468 printf (" %s\n", _("invocation arguments, the one remote program may be an agent that can")); 494 printf(" %s\n", "$ cat /tmp/foo");
469 printf (" %s\n", _("execute additional commands as proxy")); 495 printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c1;0; up 2 days");
470 printf("\n"); 496 printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c2;0; up 2 days");
471 printf (" %s\n", _("To use passive mode, provide multiple '-C' options, and provide")); 497 printf(" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c3;0; up 2 days");
472 printf (" %s\n", _("all of -O, -s, and -n options (servicelist order must match '-C'options)"));
473 printf ("\n");
474 printf ("%s\n", _("Examples:"));
475 printf (" %s\n", "$ check_by_ssh -H localhost -n lh -s c1:c2:c3 -C uptime -C uptime -C uptime -O /tmp/foo");
476 printf (" %s\n", "$ cat /tmp/foo");
477 printf (" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c1;0; up 2 days");
478 printf (" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c2;0; up 2 days");
479 printf (" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c3;0; up 2 days");
480 498
481 printf(UT_SUPPORT); 499 printf(UT_SUPPORT);
482} 500}
483 501
484 502void print_usage(void) {
485 503 printf("%s\n", _("Usage:"));
486void 504 printf(" %s -H <host> -C <command> [-fqvU] [-1|-2] [-4|-6]\n"
487print_usage (void) 505 " [-S [lines]] [-E [lines]] [-W] [-t timeout] [-i identity]\n"
488{ 506 " [-l user] [-n name] [-s servicelist] [-O outputfile]\n"
489 printf ("%s\n", _("Usage:")); 507 " [-p port] [-o ssh-option] [-F configfile]\n",
490 printf (" %s -H <host> -C <command> [-fqvU] [-1|-2] [-4|-6]\n" 508 progname);
491 " [-S [lines]] [-E [lines]] [-W] [-t timeout] [-i identity]\n"
492 " [-l user] [-n name] [-s servicelist] [-O outputfile]\n"
493 " [-p port] [-o ssh-option] [-F configfile]\n",
494 progname);
495} 509}