Code

markup 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 (_(UT_HELP_VRSN));
54         printf (_(UT_HOST_PORT), 'p', "none");
56         printf (_(UT_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 (_(UT_WARN_CRIT));
82         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
84         printf (_("\n\
85 The most common mode of use is to refer to a local identity file with\n\
86 the '-i' option. In this mode, the identity pair should have a null\n\
87 passphrase and the public key should be listed in the authorized_keys\n\
88 file of the remote host. Usually the key will be restricted to running\n\
89 only one command on the remote server. If the remote SSH server tracks\n\
90 invocation agruments, the one remote program may be an agent that can\n\
91 execute additional commands as proxy\n"));
93         printf (_("\n\
94 To use passive mode, provide multiple '-C' options, and provide\n\
95 all of -O, -s, and -n options (servicelist order must match '-C'\n\
96 options)\n"));
97 }
103 void
104 print_usage (void)
106         printf (_("Usage:\n\
107 check_by_ssh [-f46] [-t timeout] [-i identity] [-l user] -H <host> -C <command>\n\
108              [-n name] [-s servicelist] [-O outputfile] [-p port]\n\
109 check_by_ssh  -V prints version info\n\
110 check_by_ssh  -h prints more detailed help\n"));
112 \f
114 int commands = 0;
115 int services = 0;
116 char *remotecmd = "";
117 char *comm = SSH_COMMAND;
118 char *hostname = NULL;
119 char *outputfile = NULL;
120 char *host_shortname = NULL;
121 char **service;
122 int passive = FALSE;
123 int verbose = FALSE;
126 int
127 main (int argc, char **argv)
130         char input_buffer[MAX_INPUT_BUFFER];
131         char *result_text = "";
132         char *status_text;
133         char *output = "";
134         char *eol = NULL;
135         int cresult;
136         int result = STATE_UNKNOWN;
137         time_t local_time;
138         FILE *fp = NULL;
141         /* process arguments */
142         if (process_arguments (argc, argv) == ERROR)
143                 usage (_("Could not parse arguments\n"));
146         /* Set signal handling and alarm timeout */
147         if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
148                 printf ("Cannot catch SIGALRM");
149                 return STATE_UNKNOWN;
150         }
151         alarm (timeout_interval);
154         /* run the command */
156         if (verbose)
157                 printf ("%s\n", comm);
159         child_process = spopen (comm);
161         if (child_process == NULL) {
162                 printf (_("Unable to open pipe: %s"), comm);
163                 return STATE_UNKNOWN;
164         }
167         /* open STDERR  for spopen */
168         child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
169         if (child_stderr == NULL) {
170                 printf (_("Could not open stderr for %s\n"), SSH_COMMAND);
171         }
174         /* get results from remote command */
175         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process))
176                 asprintf (&result_text, "%s%s", result_text, input_buffer);
179         /* WARNING if output found on stderr */
180         if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
181                 printf ("%s\n", input_buffer);
182                 return STATE_WARNING;
183         }
184         (void) fclose (child_stderr);
187         /* close the pipe */
188         result = spclose (child_process);
191         /* process output */
192         if (passive) {
194                 if (!(fp = fopen (outputfile, "a"))) {
195                         printf (_("SSH WARNING: could not open %s\n"), outputfile);
196                         exit (STATE_UNKNOWN);
197                 }
199                 time (&local_time);
200                 commands = 0;
201                 while (result_text && strlen(result_text) > 0) {
202                         status_text = strstr (result_text, _("STATUS CODE: "));
203                         if (status_text == NULL) {
204                                 printf ("%s", result_text);
205                                 return result;
206                         }
207                         asprintf (&output, "%s", result_text);
208                         result_text = strnl (status_text);
209                         eol = strpbrk (output, "\r\n");
210                         if (eol != NULL)
211                                 eol[0] = 0;
212                         if (service[commands] && status_text
213                                         && sscanf (status_text, _("STATUS CODE: %d"), &cresult) == 1) {
214                                 fprintf (fp, _("[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n"),
215                                                                  (int) local_time, host_shortname, service[commands++], cresult,
216                                                                  output);
217                         }
218                 }
220         }
222         /* print the first line from the remote command */
223         else {
224                 eol = strpbrk (result_text, "\r\n");
225                 if (eol)
226                         eol[0] = 0;
227                 printf ("%s\n", result_text);
228         }
230         /* return error status from remote command */
231         return result;
238 /* process command-line arguments */
239 int
240 process_arguments (int argc, char **argv)
242         int c;
243         char *p1, *p2;
245         int option_index = 0;
246         static struct option long_options[] = {
247                 {"version", no_argument, 0, 'V'},
248                 {"help", no_argument, 0, 'h'},
249                 {"verbose", no_argument, 0, 'v'},
250                 {"fork", no_argument, 0, 'f'},
251                 {"timeout", required_argument, 0, 't'},
252                 {"host", required_argument, 0, 'H'},
253                 {"port", required_argument,0,'p'},
254                 {"output", required_argument, 0, 'O'},
255                 {"name", required_argument, 0, 'n'},
256                 {"services", required_argument, 0, 's'},
257                 {"identity", required_argument, 0, 'i'},
258                 {"user", required_argument, 0, 'u'},
259                 {"logname", required_argument, 0, 'l'},
260                 {"command", required_argument, 0, 'C'},
261                 {"proto1", no_argument, 0, '1'},
262                 {"proto2", no_argument, 0, '2'},
263                 {"use-ipv4", no_argument, 0, '4'},
264                 {"use-ipv6", no_argument, 0, '6'},
265                 {0, 0, 0, 0}
266         };
268         if (argc < 2)
269                 return ERROR;
271         for (c = 1; c < argc; c++)
272                 if (strcmp ("-to", argv[c]) == 0)
273                         strcpy (argv[c], "-t");
275         while (1) {
276                 c = getopt_long (argc, argv, "Vvh1246ft:H:O:p:i:u:l:C:n:s:", long_options,
277                                                                          &option_index);
279                 if (c == -1 || c == EOF)
280                         break;
282                 switch (c) {
283                 case '?':                                                                       /* help */
284                         print_usage ();
285                         exit (STATE_UNKNOWN);
286                 case 'V':                                                                       /* version */
287                         print_revision (progname, "$Revision$");
288                         exit (STATE_OK);
289                 case 'h':                                                                       /* help */
290                         print_help ();
291                         exit (STATE_OK);
292                 case 'v':                                                                       /* help */
293                         verbose = TRUE;
294                         break;
295                 case 't':                                                                       /* timeout period */
296                         if (!is_integer (optarg))
297                                 usage2 (_("timeout interval must be an integer"), optarg);
298                         timeout_interval = atoi (optarg);
299                         break;
300                 case 'H':                                                                       /* host */
301                         if (!is_host (optarg))
302                                 usage2 (_("invalid host name"), optarg);
303                         hostname = optarg;
304                         break;
305                 case 'p': /* port number */
306                         if (!is_integer (optarg))
307                                 usage2 (_("port must be an integer"), optarg);
308                         asprintf (&comm,"%s -p %s", comm, optarg);
309                         break;
310                 case 'O':                                                                       /* output file */
311                         outputfile = optarg;
312                         passive = TRUE;
313                         break;
314                 case 's':                                                                       /* description of service to check */
315                         service = realloc (service, (++services) * sizeof(char *));
316                         p1 = optarg;
317                         while ((p2 = index (p1, ':'))) {
318                                 *p2 = '\0';
319                                 asprintf (&service[services-1], "%s", p1);
320                                 service = realloc (service, (++services) * sizeof(char *));
321                                 p1 = p2 + 1;
322                         }
323                         asprintf (&service[services-1], "%s", p1);
324                         break;
325                 case 'n':                                                                       /* short name of host in nagios configuration */
326                         host_shortname = optarg;
327                         break;
328                 case 'u':
329                         c = 'l';
330                 case 'l':                                                                       /* login name */
331                 case 'i':                                                                       /* identity */
332                         asprintf (&comm, "%s -%c %s", comm, c, optarg);
333                         break;
334                 case '1':                                                                       /* Pass these switches directly to ssh */
335                 case '2':                                                                       /* 1 to force version 1, 2 to force version 2 */
336                 case '4':                                                                       /* -4 for IPv4 */
337                 case '6':                                                               /* -6 for IPv6 */
338                 case 'f':                                                                       /* fork to background */
339                         asprintf (&comm, "%s -%c", comm, c);
340                         break;
341                 case 'C':                                                                       /* Command for remote machine */
342                         commands++;
343                         if (commands > 1)
344                                 asprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
345                         asprintf (&remotecmd, "%s%s", remotecmd, optarg);
346                 }
347         }
349         c = optind;
350         if (hostname == NULL) {
351                 if (c <= argc) {
352                         die (STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname);
353                 } else if (!is_host (argv[c]))
354                         die (STATE_UNKNOWN, _("%s: Invalid host name %s\n"), progname, argv[c]);
355                 hostname = argv[c++];
356         }
358         if (strlen(remotecmd) == 0) {
359                 for (; c < argc; c++)
360                         if (strlen(remotecmd) > 0)
361                                 asprintf (&remotecmd, "%s %s", remotecmd, argv[c]);
362                         else
363                                 asprintf (&remotecmd, "%s", argv[c]);
364         }
366         if (commands > 1)
367                 remotecmd = strscat (remotecmd, ";echo STATUS CODE: $?;");
369         if (remotecmd == NULL || strlen (remotecmd) <= 1)
370                 usage (_("No remotecmd\n"));
372         asprintf (&comm, "%s %s '%s'", comm, hostname, remotecmd);
374         return validate_arguments ();
381 int
382 validate_arguments (void)
384         if (remotecmd == NULL || hostname == NULL)
385                 return ERROR;
387         if (passive && commands != services)
388                 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname);
390         if (passive && host_shortname == NULL)
391                 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the nagios configs.\n"), progname);
393         return OK;