1
/******************************************************************************
3
* This file is part of the Nagios Plugins.
5
* Copyright (c) 1999, 2000, 2001 Karl DeBisschop <karl@debisschop.net>
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.
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.
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.
21
* $Id: check_by_ssh.c,v 1.9 2003/01/29 06:15:32 kdebisschop Exp $
23
*****************************************************************************/
25
const char *progname = "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"
37
int process_arguments (int, char **);
38
int validate_arguments (void);
39
void print_help (const char *command_name);
40
void print_usage (void);
46
char *comm = SSH_COMMAND;
47
char *hostname = NULL;
48
char *outputfile = NULL;
49
char *host_shortname = NULL;
56
main (int argc, char **argv)
59
char input_buffer[MAX_INPUT_BUFFER] = "";
60
char *result_text = "";
65
char *srvc_desc = NULL;
67
int result = STATE_UNKNOWN;
72
/* process arguments */
73
if (process_arguments (argc, argv) == ERROR)
74
usage ("Could not parse arguments\n");
77
/* Set signal handling and alarm timeout */
78
if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
79
printf ("Cannot catch SIGALRM");
82
alarm (timeout_interval);
88
printf ("%s\n", comm);
90
child_process = spopen (comm);
92
if (child_process == NULL) {
93
printf ("Unable to open pipe: %s", comm);
98
/* open STDERR for spopen */
99
child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
100
if (child_stderr == NULL) {
101
printf ("Could not open stderr for %s\n", SSH_COMMAND);
105
/* get results from remote command */
106
while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process))
107
asprintf (&result_text, "%s%s", result_text, input_buffer);
110
/* WARNING if output found on stderr */
111
if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
112
printf ("%s\n", input_buffer);
113
return STATE_WARNING;
115
(void) fclose (child_stderr);
119
result = spclose (child_process);
125
if (!(fp = fopen (outputfile, "a"))) {
126
printf ("SSH WARNING: could not open %s\n", outputfile);
127
exit (STATE_UNKNOWN);
132
while (result_text && strlen(result_text) > 0) {
133
status_text = (strstr (result_text, "STATUS CODE: "));
134
if (status_text == NULL) {
135
printf ("%s", result_text);
138
asprintf (&output, "%s", result_text);
139
result_text = strnl (status_text);
140
eol = strpbrk (output, "\r\n");
143
if (service[commands] && status_text
144
&& sscanf (status_text, "STATUS CODE: %d", &cresult) == 1) {
145
fprintf (fp, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n",
146
(int) local_time, host_shortname, service[commands++], cresult,
153
/* print the first line from the remote command */
155
eol = strpbrk (result_text, "\r\n");
158
printf ("%s\n", result_text);
161
/* return error status from remote command */
169
/* process command-line arguments */
171
process_arguments (int argc, char **argv)
178
int option_index = 0;
179
static struct option long_options[] = {
180
{"version", no_argument, 0, 'V'},
181
{"help", no_argument, 0, 'h'},
182
{"verbose", no_argument, 0, 'v'},
183
{"fork", no_argument, 0, 'f'},
184
{"timeout", required_argument, 0, 't'},
185
{"host", required_argument, 0, 'H'},
186
{"port", required_argument,0,'p'},
187
{"output", required_argument, 0, 'O'},
188
{"name", required_argument, 0, 'n'},
189
{"services", required_argument, 0, 's'},
190
{"identity", required_argument, 0, 'i'},
191
{"user", required_argument, 0, 'u'},
192
{"logname", required_argument, 0, 'l'},
193
{"command", required_argument, 0, 'C'},
194
{"use-ipv4", no_argument, 0, '4'},
195
{"use-ipv6", no_argument, 0, '6'},
203
for (c = 1; c < argc; c++)
204
if (strcmp ("-to", argv[c]) == 0)
205
strcpy (argv[c], "-t");
210
getopt_long (argc, argv, "Vvh46ft:H:O:p:i:u:l:C:n:s:", long_options,
213
c = getopt (argc, argv, "Vvh46ft:H:O:p:i:u:l:C:n:s:");
216
if (c == -1 || c == EOF)
222
exit (STATE_UNKNOWN);
223
case 'V': /* version */
224
print_revision (progname, "$Revision: 1.9 $");
227
print_help (progname);
232
case 't': /* timeout period */
233
if (!is_integer (optarg))
234
usage2 ("timeout interval must be an integer", optarg);
235
timeout_interval = atoi (optarg);
238
if (!is_host (optarg))
239
usage2 ("invalid host name", optarg);
242
case 'p': /* port number */
243
if (!is_integer (optarg))
244
usage2 ("port must be an integer", optarg);
245
asprintf (&comm,"%s -p %s", comm, optarg);
247
case 'O': /* output file */
251
case 's': /* description of service to check */
252
service = realloc (service, (++services) * sizeof(char *));
254
while (p2 = index (p1, ':')) {
256
asprintf (&service[services-1], "%s", p1);
257
service = realloc (service, (++services) * sizeof(char *));
260
asprintf (&service[services-1], "%s", p1);
262
case 'n': /* short name of host in nagios configuration */
263
host_shortname = optarg;
267
case 'l': /* login name */
268
case 'i': /* identity */
269
asprintf (&comm, "%s -%c %s", comm, c, optarg);
271
case '4': /* Pass these switches directly to ssh */
272
case '6': /* -4 for IPv4, -6 for IPv6 */
273
case 'f': /* fork to background */
274
asprintf (&comm, "%s -%c", comm, c);
276
case 'C': /* Command for remote machine */
279
asprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
280
asprintf (&remotecmd, "%s%s", remotecmd, optarg);
285
if (hostname == NULL) {
287
terminate (STATE_UNKNOWN, "%s: You must provide a host name\n", progname);
288
} else if (!is_host (argv[c]))
289
terminate (STATE_UNKNOWN, "%s: Invalid host name %s\n", progname, argv[c]);
290
hostname = argv[c++];
293
if (strlen(remotecmd) == 0) {
294
for (; c < argc; c++)
295
if (strlen(remotecmd) > 0)
296
asprintf (&remotecmd, "%s %s", remotecmd, argv[c]);
298
asprintf (&remotecmd, "%s", argv[c]);
302
remotecmd = strscat (remotecmd, ";echo STATUS CODE: $?;");
304
if (remotecmd == NULL || strlen (remotecmd) <= 1)
305
usage ("No remotecmd\n");
307
asprintf (&comm, "%s %s '%s'", comm, hostname, remotecmd);
309
return validate_arguments ();
317
validate_arguments (void)
319
if (remotecmd == NULL || hostname == NULL)
322
if (passive && commands != services)
323
terminate (STATE_UNKNOWN, "%s: In passive mode, you must provide a service name for each command.\n", progname);
325
if (passive && host_shortname == NULL)
326
terminate (STATE_UNKNOWN, "%s: In passive mode, you must provide the host short name from the nagios configs.\n", progname);
336
print_help (const char *cmd)
338
print_revision (cmd, "$Revision: 1.9 $");
341
("Copyright (c) 1999 Karl DeBisschop (kdebisschop@alum.mit.edu)\n\n"
342
"This plugin will execute a command on a remote host using SSH\n\n");
348
"-H, --hostname=HOST\n"
349
" name or IP address of remote host\n"
350
"-C, --command='COMMAND STRING'\n"
351
" command to execute on the remote machine\n"
352
"-f tells ssh to fork rather than create a tty\n"
353
"-t, --timeout=INTEGER\n"
354
" specify timeout (default: %d seconds) [optional]\n"
356
" port to connect to on remote system [optional]\n"
357
"-l, --logname=USERNAME\n"
358
" SSH user name on remote host [optional]\n"
359
"-i, --identity=KEYFILE\n"
360
" identity of an authorized key [optional]\n"
361
"-O, --output=FILE\n"
362
" external command file for nagios [optional]\n"
363
"-s, --services=LIST\n"
364
" list of nagios service names, separated by ':' [optional]\n"
366
" short name of host in nagios configuration [optional]\n"
368
" tell ssh to use IPv4\n"
370
" tell ssh to use IPv6\n"
372
"The most common mode of use is to refer to a local identity file with\n"
373
"the '-i' option. In this mode, the identity pair should have a null\n"
374
"passphrase and the public key should be listed in the authorized_keys\n"
375
"file of the remote host. Usually the key will be restricted to running\n"
376
"only one command on the remote server. If the remote SSH server tracks\n"
377
"invocation agruments, the one remote program may be an agent that can\n"
378
"execute additional commands as proxy\n"
380
"To use passive mode, provide multiple '-C' options, and provide\n"
381
"all of -O, -s, and -n options (servicelist order must match '-C'\n"
382
"options)\n", DEFAULT_SOCKET_TIMEOUT);
394
"check_by_ssh [-f46] [-t timeout] [-i identity] [-l user] -H <host> -C <command>\n"
395
" [-n name] [-s servicelist] [-O outputfile] [-p port]\n"
396
"check_by_ssh -V prints version info\n"
397
"check_by_ssh -h prints more detailed help\n");