Code

mark up for translation
[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 const char *progname = "check_by_ssh";
26 const char *revision = "$Revision$";
27 const char *copyright = "2000-2003";
28 const char *email = "nagiosplug-devel@lists.sourceforge.net";
30 #include "config.h"
31 #include "common.h"
32 #include "netutils.h"
33 #include "utils.h"
34 #include "popen.h"
36 int process_arguments (int, char **);
37 int validate_arguments (void);
38 void print_help (void);
39 void print_usage (void);
41 void
42 print_help (void)
43 {
44         print_revision (progname, revision);
46         printf (_(COPYRIGHT), copyright, email);
48         printf (_("This plugin uses SSH to execute commands on a remote host\n\n"));
50         print_usage ();
52         printf (_(HELP_VRSN));
54         printf (_(HOST_PORT), 'p', "none");
56         printf (_(IPv46));
58         printf (_("\
59  -1, --proto1\n\
60     tell ssh to use Protocol 1\n\
61  -2, --proto2\n\
62     tell ssh to use Protocol 2\n\
63  -f\n\
64     tells ssh to fork rather than create a tty\n"));
66         printf (_("\
67  -C, --command='COMMAND STRING'\n\
68     command to execute on the remote machine\n\
69  -l, --logname=USERNAME\n\
70     SSH user name on remote host [optional]\n\
71  -i, --identity=KEYFILE\n\
72     identity of an authorized key [optional]\n\
73  -O, --output=FILE\n\
74     external command file for nagios [optional]\n\
75  -s, --services=LIST\n\
76     list of nagios service names, separated by ':' [optional]\n\
77  -n, --name=NAME\n\
78     short name of host in nagios configuration [optional]\n"));
80         printf (_(WARN_CRIT_TO), DEFAULT_SOCKET_TIMEOUT);
82         printf (_("\n\
83 The most common mode of use is to refer to a local identity file with\n\
84 the '-i' option. In this mode, the identity pair should have a null\n\
85 passphrase and the public key should be listed in the authorized_keys\n\
86 file of the remote host. Usually the key will be restricted to running\n\
87 only one command on the remote server. If the remote SSH server tracks\n\
88 invocation agruments, the one remote program may be an agent that can\n\
89 execute additional commands as proxy\n"));
91         printf (_("\n\
92 To use passive mode, provide multiple '-C' options, and provide\n\
93 all of -O, -s, and -n options (servicelist order must match '-C'\n\
94 options)\n"));
95 }
101 void
102 print_usage (void)
104         printf (_("Usage:\n\
105 check_by_ssh [-f46] [-t timeout] [-i identity] [-l user] -H <host> -C <command>\n\
106              [-n name] [-s servicelist] [-O outputfile] [-p port]\n\
107 check_by_ssh  -V prints version info\n\
108 check_by_ssh  -h prints more detailed help\n"));
110 \f
112 int commands = 0;
113 int services = 0;
114 char *remotecmd = "";
115 char *comm = SSH_COMMAND;
116 char *hostname = NULL;
117 char *outputfile = NULL;
118 char *host_shortname = NULL;
119 char **service;
120 int passive = FALSE;
121 int verbose = FALSE;
124 int
125 main (int argc, char **argv)
128         char input_buffer[MAX_INPUT_BUFFER];
129         char *result_text = "";
130         char *status_text;
131         char *output = "";
132         char *eol = NULL;
133         int cresult;
134         int result = STATE_UNKNOWN;
135         time_t local_time;
136         FILE *fp = NULL;
139         /* process arguments */
140         if (process_arguments (argc, argv) == ERROR)
141                 usage (_("Could not parse arguments\n"));
144         /* Set signal handling and alarm timeout */
145         if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
146                 printf ("Cannot catch SIGALRM");
147                 return STATE_UNKNOWN;
148         }
149         alarm (timeout_interval);
152         /* run the command */
154         if (verbose)
155                 printf ("%s\n", comm);
157         child_process = spopen (comm);
159         if (child_process == NULL) {
160                 printf (_("Unable to open pipe: %s"), comm);
161                 return STATE_UNKNOWN;
162         }
165         /* open STDERR  for spopen */
166         child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
167         if (child_stderr == NULL) {
168                 printf (_("Could not open stderr for %s\n"), SSH_COMMAND);
169         }
172         /* get results from remote command */
173         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process))
174                 asprintf (&result_text, "%s%s", result_text, input_buffer);
177         /* WARNING if output found on stderr */
178         if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
179                 printf ("%s\n", input_buffer);
180                 return STATE_WARNING;
181         }
182         (void) fclose (child_stderr);
185         /* close the pipe */
186         result = spclose (child_process);
189         /* process output */
190         if (passive) {
192                 if (!(fp = fopen (outputfile, "a"))) {
193                         printf (_("SSH WARNING: could not open %s\n"), outputfile);
194                         exit (STATE_UNKNOWN);
195                 }
197                 time (&local_time);
198                 commands = 0;
199                 while (result_text && strlen(result_text) > 0) {
200                         status_text = strstr (result_text, _("STATUS CODE: "));
201                         if (status_text == NULL) {
202                                 printf ("%s", result_text);
203                                 return result;
204                         }
205                         asprintf (&output, "%s", result_text);
206                         result_text = strnl (status_text);
207                         eol = strpbrk (output, "\r\n");
208                         if (eol != NULL)
209                                 eol[0] = 0;
210                         if (service[commands] && status_text
211                                         && sscanf (status_text, _("STATUS CODE: %d"), &cresult) == 1) {
212                                 fprintf (fp, _("[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n"),
213                                                                  (int) local_time, host_shortname, service[commands++], cresult,
214                                                                  output);
215                         }
216                 }
218         }
220         /* print the first line from the remote command */
221         else {
222                 eol = strpbrk (result_text, "\r\n");
223                 if (eol)
224                         eol[0] = 0;
225                 printf ("%s\n", result_text);
226         }
228         /* return error status from remote command */
229         return result;
236 /* process command-line arguments */
237 int
238 process_arguments (int argc, char **argv)
240         int c;
241         char *p1, *p2;
243         int option_index = 0;
244         static struct option long_options[] = {
245                 {"version", no_argument, 0, 'V'},
246                 {"help", no_argument, 0, 'h'},
247                 {"verbose", no_argument, 0, 'v'},
248                 {"fork", no_argument, 0, 'f'},
249                 {"timeout", required_argument, 0, 't'},
250                 {"host", required_argument, 0, 'H'},
251                 {"port", required_argument,0,'p'},
252                 {"output", required_argument, 0, 'O'},
253                 {"name", required_argument, 0, 'n'},
254                 {"services", required_argument, 0, 's'},
255                 {"identity", required_argument, 0, 'i'},
256                 {"user", required_argument, 0, 'u'},
257                 {"logname", required_argument, 0, 'l'},
258                 {"command", required_argument, 0, 'C'},
259                 {"proto1", no_argument, 0, '1'},
260                 {"proto2", no_argument, 0, '2'},
261                 {"use-ipv4", no_argument, 0, '4'},
262                 {"use-ipv6", no_argument, 0, '6'},
263                 {0, 0, 0, 0}
264         };
266         if (argc < 2)
267                 return ERROR;
269         for (c = 1; c < argc; c++)
270                 if (strcmp ("-to", argv[c]) == 0)
271                         strcpy (argv[c], "-t");
273         while (1) {
274                 c = getopt_long (argc, argv, "Vvh1246ft:H:O:p:i:u:l:C:n:s:", long_options,
275                                                                          &option_index);
277                 if (c == -1 || c == EOF)
278                         break;
280                 switch (c) {
281                 case '?':                                                                       /* help */
282                         print_usage ();
283                         exit (STATE_UNKNOWN);
284                 case 'V':                                                                       /* version */
285                         print_revision (progname, "$Revision$");
286                         exit (STATE_OK);
287                 case 'h':                                                                       /* help */
288                         print_help ();
289                         exit (STATE_OK);
290                 case 'v':                                                                       /* help */
291                         verbose = TRUE;
292                         break;
293                 case 't':                                                                       /* timeout period */
294                         if (!is_integer (optarg))
295                                 usage2 (_("timeout interval must be an integer"), optarg);
296                         timeout_interval = atoi (optarg);
297                         break;
298                 case 'H':                                                                       /* host */
299                         if (!is_host (optarg))
300                                 usage2 (_("invalid host name"), optarg);
301                         hostname = optarg;
302                         break;
303                 case 'p': /* port number */
304                         if (!is_integer (optarg))
305                                 usage2 (_("port must be an integer"), optarg);
306                         asprintf (&comm,"%s -p %s", comm, optarg);
307                         break;
308                 case 'O':                                                                       /* output file */
309                         outputfile = optarg;
310                         passive = TRUE;
311                         break;
312                 case 's':                                                                       /* description of service to check */
313                         service = realloc (service, (++services) * sizeof(char *));
314                         p1 = optarg;
315                         while ((p2 = index (p1, ':'))) {
316                                 *p2 = '\0';
317                                 asprintf (&service[services-1], "%s", p1);
318                                 service = realloc (service, (++services) * sizeof(char *));
319                                 p1 = p2 + 1;
320                         }
321                         asprintf (&service[services-1], "%s", p1);
322                         break;
323                 case 'n':                                                                       /* short name of host in nagios configuration */
324                         host_shortname = optarg;
325                         break;
326                 case 'u':
327                         c = 'l';
328                 case 'l':                                                                       /* login name */
329                 case 'i':                                                                       /* identity */
330                         asprintf (&comm, "%s -%c %s", comm, c, optarg);
331                         break;
332                 case '1':                                                                       /* Pass these switches directly to ssh */
333                 case '2':                                                                       /* 1 to force version 1, 2 to force version 2 */
334                 case '4':                                                                       /* -4 for IPv4 */
335                 case '6':                                                               /* -6 for IPv6 */
336                 case 'f':                                                                       /* fork to background */
337                         asprintf (&comm, "%s -%c", comm, c);
338                         break;
339                 case 'C':                                                                       /* Command for remote machine */
340                         commands++;
341                         if (commands > 1)
342                                 asprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
343                         asprintf (&remotecmd, "%s%s", remotecmd, optarg);
344                 }
345         }
347         c = optind;
348         if (hostname == NULL) {
349                 if (c <= argc) {
350                         terminate (STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname);
351                 } else if (!is_host (argv[c]))
352                         terminate (STATE_UNKNOWN, _("%s: Invalid host name %s\n"), progname, argv[c]);
353                 hostname = argv[c++];
354         }
356         if (strlen(remotecmd) == 0) {
357                 for (; c < argc; c++)
358                         if (strlen(remotecmd) > 0)
359                                 asprintf (&remotecmd, "%s %s", remotecmd, argv[c]);
360                         else
361                                 asprintf (&remotecmd, "%s", argv[c]);
362         }
364         if (commands > 1)
365                 remotecmd = strscat (remotecmd, ";echo STATUS CODE: $?;");
367         if (remotecmd == NULL || strlen (remotecmd) <= 1)
368                 usage (_("No remotecmd\n"));
370         asprintf (&comm, "%s %s '%s'", comm, hostname, remotecmd);
372         return validate_arguments ();
379 int
380 validate_arguments (void)
382         if (remotecmd == NULL || hostname == NULL)
383                 return ERROR;
385         if (passive && commands != services)
386                 terminate (STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname);
388         if (passive && host_shortname == NULL)
389                 terminate (STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the nagios configs.\n"), progname);
391         return OK;