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.c412
1 files changed, 412 insertions, 0 deletions
diff --git a/plugins/check_by_ssh.c b/plugins/check_by_ssh.c
new file mode 100644
index 00000000..a81b333f
--- /dev/null
+++ b/plugins/check_by_ssh.c
@@ -0,0 +1,412 @@
1/******************************************************************************
2 *
3 * This file is part of the Nagios Plugins.
4 *
5 * Copyright (c) 1999, 2000, 2001 Karl DeBisschop <karl@debisschop.net>
6 *
7 * The Nagios Plugins are free software; you can redistribute them
8 * and/or modify them under the terms of the GNU General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 * $Id$
22 *
23 *****************************************************************************/
24
25#define PROGRAM check_by_ssh
26#define DESCRIPTION "Run checks on a remote system using ssh, wrapping the proper timeout around the ssh invocation."
27#define AUTHOR "Karl DeBisschop"
28#define EMAIL "karl@debisschop.net"
29#define COPYRIGHTDATE "1999, 2000, 2001"
30
31#include "config.h"
32#include "common.h"
33#include "popen.h"
34#include "utils.h"
35#include <time.h>
36
37#define PROGNAME "check_by_ssh"
38
39int process_arguments (int, char **);
40int call_getopt (int, char **);
41int validate_arguments (void);
42void print_help (char *command_name);
43void print_usage (void);
44
45
46int commands;
47char *remotecmd = NULL;
48char *comm = NULL;
49char *hostname = NULL;
50char *outputfile = NULL;
51char *host_shortname = NULL;
52char *servicelist = NULL;
53int passive = FALSE;
54int verbose = FALSE;
55
56
57int
58main (int argc, char **argv)
59{
60
61 char input_buffer[MAX_INPUT_BUFFER] = "";
62 char *result_text = NULL;
63 char *status_text;
64 char *output = NULL;
65 char *eol = NULL;
66 char *srvc_desc = NULL;
67 int cresult;
68 int result = STATE_UNKNOWN;
69 time_t local_time;
70 FILE *fp = NULL;
71
72
73 /* process arguments */
74 if (process_arguments (argc, argv) == ERROR)
75 usage ("Could not parse arguments\n");
76
77
78 /* Set signal handling and alarm timeout */
79 if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
80 printf ("Cannot catch SIGALRM");
81 return STATE_UNKNOWN;
82 }
83 alarm (timeout_interval);
84
85
86 /* run the command */
87
88 if (verbose)
89 printf ("%s\n", comm);
90
91 child_process = spopen (comm);
92
93 if (child_process == NULL) {
94 printf ("Unable to open pipe: %s", comm);
95 return STATE_UNKNOWN;
96 }
97
98
99 /* open STDERR for spopen */
100 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
101 if (child_stderr == NULL) {
102 printf ("Could not open stderr for %s\n", SSH_COMMAND);
103 }
104
105
106 /* get results from remote command */
107 result_text = realloc (result_text, 1);
108 result_text[0] = 0;
109 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process))
110 result_text = strscat (result_text, input_buffer);
111
112
113 /* WARNING if output found on stderr */
114 if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
115 printf ("%s\n", input_buffer);
116 return STATE_WARNING;
117 }
118 (void) fclose (child_stderr);
119
120
121 /* close the pipe */
122 result = spclose (child_process);
123
124
125 /* process output */
126 if (passive) {
127
128 if (!(fp = fopen (outputfile, "a"))) {
129 printf ("SSH WARNING: could not open %s\n", outputfile);
130 exit (STATE_UNKNOWN);
131 }
132
133 time (&local_time);
134 srvc_desc = strtok (servicelist, ":");
135 while (result_text != NULL) {
136 status_text = (strstr (result_text, "STATUS CODE: "));
137 if (status_text == NULL) {
138 printf ("%s", result_text);
139 return result;
140 }
141 output = result_text;
142 result_text = strnl (status_text);
143 eol = strpbrk (output, "\r\n");
144 if (eol != NULL)
145 eol[0] = 0;
146 if (srvc_desc && status_text
147 && sscanf (status_text, "STATUS CODE: %d", &cresult) == 1) {
148 fprintf (fp, "%d PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n",
149 (int) local_time, host_shortname, srvc_desc, cresult,
150 output);
151 srvc_desc = strtok (NULL, ":");
152 }
153 }
154
155 }
156
157 /* print the first line from the remote command */
158 else {
159 eol = strpbrk (result_text, "\r\n");
160 if (eol)
161 eol[0] = 0;
162 printf ("%s\n", result_text);
163
164 }
165
166
167 /* return error status from remote command */
168 return result;
169}
170
171
172
173
174
175/* process command-line arguments */
176int
177process_arguments (int argc, char **argv)
178{
179 int c;
180
181 if (argc < 2)
182 return ERROR;
183
184 remotecmd = realloc (remotecmd, 1);
185 remotecmd[0] = 0;
186
187 for (c = 1; c < argc; c++)
188 if (strcmp ("-to", argv[c]) == 0)
189 strcpy (argv[c], "-t");
190
191 comm = strscpy (comm, SSH_COMMAND);
192
193 c = 0;
194 while (c += (call_getopt (argc - c, &argv[c]))) {
195
196 if (argc <= c)
197 break;
198
199 if (hostname == NULL) {
200 if (!is_host (argv[c]))
201 terminate (STATE_UNKNOWN, "%s: Invalid host name %s\n", PROGNAME,
202 argv[c]);
203 hostname = argv[c];
204 }
205 else if (remotecmd == NULL) {
206 remotecmd = strscpy (remotecmd, argv[c++]);
207 for (; c < argc; c++)
208 remotecmd = ssprintf (remotecmd, "%s %s", remotecmd, argv[c]);
209 }
210
211 }
212
213 if (commands > 1)
214 remotecmd = strscat (remotecmd, ";echo STATUS CODE: $?;");
215
216 if (remotecmd == NULL || strlen (remotecmd) <= 1)
217 usage ("No remotecmd\n");
218
219 comm = ssprintf (comm, "%s %s '%s'", comm, hostname, remotecmd);
220
221 return validate_arguments ();
222}
223
224
225
226
227
228/* Call getopt */
229int
230call_getopt (int argc, char **argv)
231{
232 int c, i = 1;
233
234#ifdef HAVE_GETOPT_H
235 int option_index = 0;
236 static struct option long_options[] = {
237 {"version", no_argument, 0, 'V'},
238 {"help", no_argument, 0, 'h'},
239 {"verbose", no_argument, 0, 'v'},
240 {"fork", no_argument, 0, 'f'},
241 {"timeout", required_argument, 0, 't'},
242 {"host", required_argument, 0, 'H'},
243 {"port", required_argument,0,'P'},
244 {"output", required_argument, 0, 'O'},
245 {"name", required_argument, 0, 'n'},
246 {"services", required_argument, 0, 's'},
247 {"identity", required_argument, 0, 'i'},
248 {"user", required_argument, 0, 'u'},
249 {"logname", required_argument, 0, 'l'},
250 {"command", required_argument, 0, 'C'},
251 {0, 0, 0, 0}
252 };
253#endif
254
255 while (1) {
256#ifdef HAVE_GETOPT_H
257 c =
258 getopt_long (argc, argv, "+?Vvhft:H:O:P:p:i:u:l:C:n:s:", long_options,
259 &option_index);
260#else
261 c = getopt (argc, argv, "+?Vvhft:H:O:P:p:i:u:l:C:n:s:");
262#endif
263
264 if (c == -1 || c == EOF)
265 break;
266
267 i++;
268 switch (c) {
269 case 't':
270 case 'H':
271 case 'O':
272 case 'p':
273 case 'i':
274 case 'u':
275 case 'l':
276 case 'n':
277 case 's':
278 i++;
279 }
280
281 switch (c) {
282 case '?': /* help */
283 print_usage ();
284 exit (STATE_UNKNOWN);
285 case 'V': /* version */
286 print_revision (PROGNAME, "$Revision$");
287 exit (STATE_OK);
288 case 'h': /* help */
289 print_help (PROGNAME);
290 exit (STATE_OK);
291 case 'v': /* help */
292 verbose = TRUE;
293 break;
294 case 'f': /* fork to background */
295 comm = ssprintf (comm, "%s -f", comm);
296 break;
297 case 't': /* timeout period */
298 if (!is_integer (optarg))
299 usage2 ("timeout interval must be an integer", optarg);
300 timeout_interval = atoi (optarg);
301 break;
302 case 'H': /* host */
303 if (!is_host (optarg))
304 usage2 ("invalid host name", optarg);
305 hostname = optarg;
306 break;
307 case 'P': /* port number */
308 case 'p': /* port number */
309 if (!is_integer (optarg))
310 usage2 ("port must be an integer", optarg);
311 comm = ssprintf (comm,"%s -p %s", comm, optarg);
312 break;
313 case 'O': /* output file */
314 outputfile = optarg;
315 passive = TRUE;
316 break;
317 case 's': /* description of service to check */
318 servicelist = optarg;
319 break;
320 case 'n': /* short name of host in nagios configuration */
321 host_shortname = optarg;
322 break;
323 case 'u':
324 c = 'l';
325 case 'l': /* login name */
326 case 'i': /* identity */
327 comm = ssprintf (comm, "%s -%c %s", comm, c, optarg);
328 break;
329 case 'C': /* Command for remote machine */
330 commands++;
331 if (commands > 1)
332 remotecmd = strscat (remotecmd, ";echo STATUS CODE: $?;");
333 remotecmd = strscat (remotecmd, optarg);
334 }
335 }
336 return i;
337}
338
339
340
341
342
343int
344validate_arguments (void)
345{
346 if (remotecmd == NULL || hostname == NULL)
347 return ERROR;
348 return OK;
349}
350
351
352
353
354
355void
356print_help (char *cmd)
357{
358 print_revision (cmd, "$Revision$");
359
360 printf
361 ("Copyright (c) 1999 Karl DeBisschop (kdebisschop@alum.mit.edu)\n\n"
362 "This plugin will execute a command on a remote host using SSH\n\n");
363
364 print_usage ();
365
366 printf
367 ("\nOptions:\n"
368 "-H, --hostname=HOST\n"
369 " name or IP address of remote host\n"
370 "-C, --command='COMMAND STRING'\n"
371 " command to execute on the remote machine\n"
372 "-f tells ssh to fork rather than create a tty\n"
373 "-t, --timeout=INTEGER\n"
374 " specify timeout (default: %d seconds) [optional]\n"
375 "-l, --logname=USERNAME\n"
376 " SSH user name on remote host [optional]\n"
377 "-i, --identity=KEYFILE\n"
378 " identity of an authorized key [optional]\n"
379 "-O, --output=FILE\n"
380 " external command file for nagios [optional]\n"
381 "-s, --services=LIST\n"
382 " list of nagios service names, separated by ':' [optional]\n"
383 "-n, --name=NAME\n"
384 " short name of host in nagios configuration [optional]\n"
385 "\n"
386 "The most common mode of use is to refer to a local identity file with\n"
387 "the '-i' option. In this mode, the identity pair should have a null\n"
388 "passphrase and the public key should be listed in the authorized_keys\n"
389 "file of the remote host. Usually the key will be restricted to running\n"
390 "only one command on the remote server. If the remote SSH server tracks\n"
391 "invocation agruments, the one remote program may be an agent that can\n"
392 "execute additional commands as proxy\n"
393 "\n"
394 "To use passive mode, provide multiple '-C' options, and provide\n"
395 "all of -O, -s, and -n options (servicelist order must match '-C'\n"
396 "options)\n", DEFAULT_SOCKET_TIMEOUT);
397}
398
399
400
401
402
403void
404print_usage (void)
405{
406 printf
407 ("Usage:\n"
408 "check_by_ssh [-f] [-t timeout] [-i identity] [-l user] -H <host> <command>\n"
409 " [-n name] [-s servicelist] [-O outputfile] [-P port]\n"
410 "check_by_ssh -V prints version info\n"
411 "check_by_ssh -h prints more detailed help\n");
412}