Code

changed Error: by CRITICAL -
[nagiosplug.git] / plugins / check_by_ssh.c
1 /******************************************************************************
3  The Nagios Plugins are free software; you can redistribute them
4  and/or modify them under the terms of the GNU General Public
5  License as published by the Free Software Foundation; either
6  version 2 of the License, or (at your option) any later version.
8  This program is distributed in the hope that it will be useful, but
9  WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  General Public License for more details.
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  $Id$
18  
19  *****************************************************************************/
20  
21 const char *progname = "check_by_ssh";
22 const char *revision = "$Revision$";
23 const char *copyright = "2000-2003";
24 const char *email = "nagiosplug-devel@lists.sourceforge.net";
26 #include "common.h"
27 #include "netutils.h"
28 #include "utils.h"
29 #include "popen.h"
31 int process_arguments (int, char **);
32 int validate_arguments (void);
33 void print_help (void);
34 void print_usage (void);
36 int commands = 0;
37 int services = 0;
38 int skip_lines = 0;
39 char *remotecmd = NULL;
40 char *comm = NULL;
41 char *hostname = NULL;
42 char *outputfile = NULL;
43 char *host_shortname = NULL;
44 char **service;
45 int passive = FALSE;
46 int verbose = FALSE;
48 int
49 main (int argc, char **argv)
50 {
52         char input_buffer[MAX_INPUT_BUFFER];
53         char *result_text;
54         char *status_text;
55         char *output;
56         char *eol = NULL;
57         int cresult;
58         int result = STATE_UNKNOWN;
59         time_t local_time;
60         FILE *fp = NULL;
62         remotecmd = strdup ("");
63         comm = strdup (SSH_COMMAND);
64         result_text = strdup ("");
66         setlocale (LC_ALL, "");
67         bindtextdomain (PACKAGE, LOCALEDIR);
68         textdomain (PACKAGE);
70         /* process arguments */
71         if (process_arguments (argc, argv) == ERROR)
72                 usage (_("check_by_ssh: could not parse arguments\n"));
75         /* Set signal handling and alarm timeout */
76         if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
77                 printf (_("Cannot catch SIGALRM"));
78                 return STATE_UNKNOWN;
79         }
80         alarm (timeout_interval);
83         /* run the command */
85         if (verbose)
86                 printf ("%s\n", comm);
88         child_process = spopen (comm);
90         if (child_process == NULL) {
91                 printf (_("Could not open pipe: %s\n"), comm);
92                 return STATE_UNKNOWN;
93         }
96         /* open STDERR  for spopen */
97         child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
98         if (child_stderr == NULL) {
99                 printf (_("Could not open stderr for %s\n"), SSH_COMMAND);
100         }
103         /* build up results from remote command in result_text */
104         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process))
105                 asprintf (&result_text, "%s%s", result_text, input_buffer);
107         /* WARNING if output found on stderr */
108         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
109                 if (skip_lines > 0) {
110                         if (input_buffer[strlen(input_buffer)-1] == '\n') {
111                                 skip_lines--;
112                         }
113                 } else {
114                         printf ("%s", input_buffer);
115                         result = STATE_WARNING;
116                 }
117         }
118         (void) fclose (child_stderr);
119         if (result == STATE_WARNING)
120                 return result;
123         /* close the pipe */
124         result = spclose (child_process);
127         /* process output */
128         if (passive) {
130                 if (!(fp = fopen (outputfile, "a"))) {
131                         printf (_("SSH WARNING: could not open %s\n"), outputfile);
132                         exit (STATE_UNKNOWN);
133                 }
135                 local_time = time (NULL);
136                 commands = 0;
137                 while (result_text && strlen(result_text) > 0) {
138                         status_text = strstr (result_text, "STATUS CODE: ");
139                         if (status_text == NULL) {
140                                 printf ("%s", result_text);
141                                 return result;
142                         }
143                         asprintf (&output, "%s", result_text);
144                         result_text = strnl (status_text);
145                         eol = strpbrk (output, "\r\n");
146                         if (eol != NULL)
147                                 eol[0] = 0;
148                         if (service[commands] && status_text
149                                         && sscanf (status_text, "STATUS CODE: %d", &cresult) == 1) {
150                                 fprintf (fp, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n",
151                                                                  (int) local_time, host_shortname, service[commands++], cresult,
152                                                                  output);
153                         }
154                 }
156         }
159         /* print the first line from the remote command */
160         else {
161                 eol = strpbrk (result_text, "\r\n");
162                 if (eol)
163                         eol[0] = 0;
164                 printf ("%s\n", result_text);
165         }
168         /* return error status from remote command */   
169         return result;
172 /* process command-line arguments */
173 int
174 process_arguments (int argc, char **argv)
176         int c;
177         char *p1, *p2;
179         int option = 0;
180         static struct option longopts[] = {
181                 {"version", no_argument, 0, 'V'},
182                 {"help", no_argument, 0, 'h'},
183                 {"verbose", no_argument, 0, 'v'},
184                 {"fork", no_argument, 0, 'f'},
185                 {"timeout", required_argument, 0, 't'},
186                 {"host", required_argument, 0, 'H'},
187                 {"port", required_argument,0,'p'},
188                 {"output", required_argument, 0, 'O'},
189                 {"name", required_argument, 0, 'n'},
190                 {"services", required_argument, 0, 's'},
191                 {"identity", required_argument, 0, 'i'},
192                 {"user", required_argument, 0, 'u'},
193                 {"logname", required_argument, 0, 'l'},
194                 {"command", required_argument, 0, 'C'},
195                 {"skip", required_argument, 0, 'S'},
196                 {"proto1", no_argument, 0, '1'},
197                 {"proto2", no_argument, 0, '2'},
198                 {"use-ipv4", no_argument, 0, '4'},
199                 {"use-ipv6", no_argument, 0, '6'},
200                 {0, 0, 0, 0}
201         };
203         if (argc < 2)
204                 return ERROR;
206         for (c = 1; c < argc; c++)
207                 if (strcmp ("-to", argv[c]) == 0)
208                         strcpy (argv[c], "-t");
210         while (1) {
211                 c = getopt_long (argc, argv, "Vvh1246ft:H:O:p:i:u:l:C:S:n:s:", longopts,
212                                                                          &option);
214                 if (c == -1 || c == EOF)
215                         break;
217                 switch (c) {
218                 case '?':                                                                       /* help */
219                         printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
220                         print_usage ();
221                         exit (STATE_UNKNOWN);
222                 case 'V':                                                                       /* version */
223                         print_revision (progname, revision);
224                         exit (STATE_OK);
225                 case 'h':                                                                       /* help */
226                         print_help ();
227                         exit (STATE_OK);
228                 case 'v':                                                                       /* help */
229                         verbose = TRUE;
230                         break;
231                 case 't':                                                                       /* timeout period */
232                         if (!is_integer (optarg))
233                                 usage2 (_("Timeout interval must be a positive integer"), optarg);
234                         else
235                                 timeout_interval = atoi (optarg);
236                         break;
237                 case 'H':                                                                       /* host */
238                         if (!is_host (optarg))
239                                 usage2 (_("Invalid hostname/address"), optarg);
240                         hostname = optarg;
241                         break;
242                 case 'p': /* port number */
243                         if (!is_integer (optarg))
244                                 usage2 (_("Port must be a positive integer"), optarg);
245                         asprintf (&comm,"%s -p %s", comm, optarg);
246                         break;
247                 case 'O':                                                                       /* output file */
248                         outputfile = optarg;
249                         passive = TRUE;
250                         break;
251                 case 's':                                                                       /* description of service to check */
252                         service = realloc (service, (++services) * sizeof(char *));
253                         p1 = optarg;
254                         while ((p2 = index (p1, ':'))) {
255                                 *p2 = '\0';
256                                 asprintf (&service[services-1], "%s", p1);
257                                 service = realloc (service, (++services) * sizeof(char *));
258                                 p1 = p2 + 1;
259                         }
260                         asprintf (&service[services-1], "%s", p1);
261                         break;
262                 case 'n':                                                                       /* short name of host in nagios configuration */
263                         host_shortname = optarg;
264                         break;
265                 case 'u':
266                         c = 'l';
267                 case 'l':                                                                       /* login name */
268                 case 'i':                                                                       /* identity */
269                         asprintf (&comm, "%s -%c %s", comm, c, optarg);
270                         break;
271                 case '1':                                                                       /* Pass these switches directly to ssh */
272                 case '2':                                                                       /* 1 to force version 1, 2 to force version 2 */
273                 case '4':                                                                       /* -4 for IPv4 */
274                 case '6':                                                               /* -6 for IPv6 */
275                 case 'f':                                                                       /* fork to background */
276                         asprintf (&comm, "%s -%c", comm, c);
277                         break;
278                 case 'C':                                                                       /* Command for remote machine */
279                         commands++;
280                         if (commands > 1)
281                                 asprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
282                         asprintf (&remotecmd, "%s%s", remotecmd, optarg);
283                         break;
284                 case 'S':                                                                       /* Skip n lines in the output to ignore system banner */
285                         if (!is_integer (optarg))
286                                 usage2 (_("skip lines must be an integer"), optarg);
287                         else
288                                 skip_lines = atoi (optarg);
289                         break;
290                 }
291         }
293         c = optind;
294         if (hostname == NULL) {
295                 if (c <= argc) {
296                         die (STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname);
297                 } else if (!is_host (argv[c]))
298                         die (STATE_UNKNOWN, "%s: %s %s\n", progname, _("Invalid hostname/address"), argv[c]);
299                 hostname = argv[c++];
300         }
302         if (strlen(remotecmd) == 0) {
303                 for (; c < argc; c++)
304                         if (strlen(remotecmd) > 0)
305                                 asprintf (&remotecmd, "%s %s", remotecmd, argv[c]);
306                         else
307                                 asprintf (&remotecmd, "%s", argv[c]);
308         }
310         if (commands > 1)
311                 asprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
313         if (remotecmd == NULL || strlen (remotecmd) <= 1)
314                 usage (_("No remotecmd\n"));
316         asprintf (&comm, "%s %s '%s'", comm, hostname, remotecmd);
318         return validate_arguments ();
323 int
324 validate_arguments (void)
326         if (remotecmd == NULL || hostname == NULL)
327                 return ERROR;
329         if (passive && commands != services)
330                 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname);
332         if (passive && host_shortname == NULL)
333                 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the nagios configs.\n"), progname);
335         return OK;
339 void
340 print_help (void)
342         print_revision (progname, revision);
344         printf (_("Copyright (c) 1999 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n"));
345         printf (_(COPYRIGHT), copyright, email);
347         printf (_("This plugin uses SSH to execute commands on a remote host\n\n"));
349         print_usage ();
351         printf (_(UT_HELP_VRSN));
353         printf (_(UT_HOST_PORT), 'p', "none");
355         printf (_(UT_IPv46));
357         printf (_("\
358  -1, --proto1\n\
359     tell ssh to use Protocol 1\n\
360  -2, --proto2\n\
361     tell ssh to use Protocol 2\n\
362  -S, --skiplines=n\n\
363     Ignore first n lines on STDERR (to suppress a logon banner)\n\
364  -f\n\
365     tells ssh to fork rather than create a tty\n"));
367         printf (_("\
368  -C, --command='COMMAND STRING'\n\
369     command to execute on the remote machine\n\
370  -l, --logname=USERNAME\n\
371     SSH user name on remote host [optional]\n\
372  -i, --identity=KEYFILE\n\
373     identity of an authorized key [optional]\n\
374  -O, --output=FILE\n\
375     external command file for nagios [optional]\n\
376  -s, --services=LIST\n\
377     list of nagios service names, separated by ':' [optional]\n\
378  -n, --name=NAME\n\
379     short name of host in nagios configuration [optional]\n"));
381         printf (_(UT_WARN_CRIT));
383         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
385         printf (_("\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"));
394         printf (_("\n\
395 To use passive mode, provide multiple '-C' options, and provide\n\
396 all of -O, -s, and -n options (servicelist order must match '-C'\n\
397 options)\n"));
399         printf (_("\n\
400 $ check_by_ssh -H localhost -n lh -s c1:c2:c3 \\\n\
401     -C uptime -C uptime -C uptime -O /tmp/foo\n\
402 $ cat /tmp/foo\n\
403 [1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c1;0; up 2 days...\n\
404 [1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c2;0; up 2 days...\n\
405 [1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c3;0; up 2 days...\n"));
407         printf (_(UT_SUPPORT));
412 void
413 print_usage (void)
415         printf (_("\n\
416 Usage: %s [-f46] [-t timeout] [-i identity] [-l user] -H <host> \n\
417   -C <command> [-n name] [-s servicelist] [-O outputfile] [-p port]\n"),
418                 progname);
419         printf (_(UT_HLP_VRS), progname, progname);