Code

debian builds not actively maintained, so suppress error in setup script
[nagiosplug.git] / plugins / check_by_ssh.c
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"
31 #include "config.h"
32 #include "common.h"
33 #include "popen.h"
34 #include "utils.h"
35 #include <time.h>
37 #define PROGNAME "check_by_ssh"
39 int process_arguments (int, char **);
40 int call_getopt (int, char **);
41 int validate_arguments (void);
42 void print_help (char *command_name);
43 void print_usage (void);
46 int commands;
47 char *remotecmd = NULL;
48 char *comm = NULL;
49 char *hostname = NULL;
50 char *outputfile = NULL;
51 char *host_shortname = NULL;
52 char *servicelist = NULL;
53 int passive = FALSE;
54 int verbose = FALSE;
57 int
58 main (int argc, char **argv)
59 {
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;
73         /* process arguments */
74         if (process_arguments (argc, argv) == ERROR)
75                 usage ("Could not parse arguments\n");
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);
86         /* run the command */
88         if (verbose)
89                 printf ("%s\n", comm);
91         child_process = spopen (comm);
93         if (child_process == NULL) {
94                 printf ("Unable to open pipe: %s", comm);
95                 return STATE_UNKNOWN;
96         }
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         }
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);
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);
121         /* close the pipe */
122         result = spclose (child_process);
125         /* process output */
126         if (passive) {
128                 if (!(fp = fopen (outputfile, "a"))) {
129                         printf ("SSH WARNING: could not open %s\n", outputfile);
130                         exit (STATE_UNKNOWN);
131                 }
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                 }
155         }
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);
164         }
167         /* return error status from remote command */
168         return result;
175 /* process command-line arguments */
176 int
177 process_arguments (int argc, char **argv)
179         int c;
181         if (argc < 2)
182                 return ERROR;
184         remotecmd = realloc (remotecmd, 1);
185         remotecmd[0] = 0;
187         for (c = 1; c < argc; c++)
188                 if (strcmp ("-to", argv[c]) == 0)
189                         strcpy (argv[c], "-t");
191         comm = strscpy (comm, SSH_COMMAND);
193         c = 0;
194         while (c += (call_getopt (argc - c, &argv[c]))) {
196                 if (argc <= c)
197                         break;
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                 }
211         }
213         if (commands > 1)
214                 remotecmd = strscat (remotecmd, ";echo STATUS CODE: $?;");
216         if (remotecmd == NULL || strlen (remotecmd) <= 1)
217                 usage ("No remotecmd\n");
219         comm = ssprintf (comm, "%s %s '%s'", comm, hostname, remotecmd);
221         return validate_arguments ();
228 /* Call getopt */
229 int
230 call_getopt (int argc, char **argv)
232         int c, i = 1;
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                 {"use-ipv4", no_argument, 0, '4'},
252                 {"use-ipv6", no_argument, 0, '6'},
253                 {0, 0, 0, 0}
254         };
255 #endif
257         while (1) {
258 #ifdef HAVE_GETOPT_H
259                 c =
260                         getopt_long (argc, argv, "+?Vvhft46H:O:p:i:u:l:C:n:s:", long_options,
261                                                                          &option_index);
262 #else
263                 c = getopt (argc, argv, "+?Vvhft46H:O:p:i:u:l:C:n:s:");
264 #endif
266                 if (c == -1 || c == EOF)
267                         break;
269                 i++;
270                 switch (c) {
271                 case 't':
272                 case 'H':
273                 case 'O':
274                 case 'p':
275                 case 'i':
276                 case 'u':
277                 case 'l':
278                 case 'n':
279                 case 's':
280                         i++;
281                 }
283                 switch (c) {
284                 case '?':                                                                       /* help */
285                         print_usage ();
286                         exit (STATE_UNKNOWN);
287                 case 'V':                                                                       /* version */
288                         print_revision (PROGNAME, "$Revision$");
289                         exit (STATE_OK);
290                 case 'h':                                                                       /* help */
291                         print_help (PROGNAME);
292                         exit (STATE_OK);
293                 case 'v':                                                                       /* help */
294                         verbose = TRUE;
295                         break;
296                 case 't':                                                                       /* timeout period */
297                         if (!is_integer (optarg))
298                                 usage2 ("timeout interval must be an integer", optarg);
299                         timeout_interval = atoi (optarg);
300                         break;
301                 case 'H':                                                                       /* host */
302                         if (!is_host (optarg))
303                                 usage2 ("invalid host name", optarg);
304                         hostname = optarg;
305                         break;
306                 case 'p': /* port number */
307                         if (!is_integer (optarg))
308                                 usage2 ("port must be an integer", optarg);
309                         comm = ssprintf (comm,"%s -p %s", comm, optarg);
310                         break;
311                 case 'O':                                                                       /* output file */
312                         outputfile = optarg;
313                         passive = TRUE;
314                         break;
315                 case 's':                                                                       /* description of service to check */
316                         servicelist = optarg;
317                         break;
318                 case 'n':                                                                       /* short name of host in nagios configuration */
319                         host_shortname = optarg;
320                         break;
321                 case 'u':
322                         c = 'l';
323                 case 'l':                                                                       /* login name */
324                 case 'i':                                                                       /* identity */
325                         comm = ssprintf (comm, "%s -%c %s", comm, c, optarg);
326                         break;
327                 case '4':                                                                       /* Pass these switches directly to ssh */
328                 case '6':                                                               /* -4 for IPv4, -6 for IPv6 */
329                 case 'f':                                                                       /* fork to background */
330                         comm = ssprintf (comm, "%s -%c", comm, c);
331                         break;
332                 case 'C':                                                                       /* Command for remote machine */
333                         commands++;
334                         if (commands > 1)
335                                 remotecmd = strscat (remotecmd, ";echo STATUS CODE: $?;");
336                         remotecmd = strscat (remotecmd, optarg);
337                 }
338         }
339         return i;
346 int
347 validate_arguments (void)
349         if (remotecmd == NULL || hostname == NULL)
350                 return ERROR;
351         return OK;
358 void
359 print_help (char *cmd)
361         print_revision (cmd, "$Revision$");
363         printf
364                 ("Copyright (c) 1999    Karl DeBisschop (kdebisschop@alum.mit.edu)\n\n"
365                  "This plugin will execute a command on a remote host using SSH\n\n");
367         print_usage ();
369         printf
370                 ("\nOptions:\n"
371                  "-H, --hostname=HOST\n"
372                  "   name or IP address of remote host\n"
373                  "-C, --command='COMMAND STRING'\n"
374                  "   command to execute on the remote machine\n"
375                  "-f tells ssh to fork rather than create a tty\n"
376                  "-t, --timeout=INTEGER\n"
377                  "   specify timeout (default: %d seconds) [optional]\n"
378                  "-p, --port=PORT\n"
379                  "   port to connect to on remote system [optional]\n"
380          "-l, --logname=USERNAME\n"
381                  "   SSH user name on remote host [optional]\n"
382                  "-i, --identity=KEYFILE\n"
383                  "   identity of an authorized key [optional]\n"
384                  "-O, --output=FILE\n"
385                  "   external command file for nagios [optional]\n"
386                  "-s, --services=LIST\n"
387                  "   list of nagios service names, separated by ':' [optional]\n"
388                  "-n, --name=NAME\n"
389                  "   short name of host in nagios configuration [optional]\n"
390                  "-4, --use-ipv4\n"
391                  "   tell ssh to use IPv4\n"
392                  "-6, --use-ipv6\n"
393                  "   tell ssh to use IPv6\n"
394                  "\n"
395                  "The most common mode of use is to refer to a local identity file with\n"
396                  "the '-i' option. In this mode, the identity pair should have a null\n"
397                  "passphrase and the public key should be listed in the authorized_keys\n"
398                  "file of the remote host. Usually the key will be restricted to running\n"
399                  "only one command on the remote server. If the remote SSH server tracks\n"
400                  "invocation agruments, the one remote program may be an agent that can\n"
401                  "execute additional commands as proxy\n"
402                  "\n"
403                  "To use passive mode, provide multiple '-C' options, and provide\n"
404                  "all of -O, -s, and -n options (servicelist order must match '-C'\n"
405                  "options)\n", DEFAULT_SOCKET_TIMEOUT);
412 void
413 print_usage (void)
415         printf
416                 ("Usage:\n"
417                  "check_by_ssh [-f46] [-t timeout] [-i identity] [-l user] -H <host> -C <command>\n"
418                  "             [-n name] [-s servicelist] [-O outputfile] [-p port]\n"
419                  "check_by_ssh  -V prints version info\n"
420                  "check_by_ssh  -h prints more detailed help\n");