Code

Convert tabs to spaces from dig's answer section (Randy O'Meara - 1107651)
[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-2004";
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                 usage4 (_("Could not parse arguments"));
74         /* Set signal handling and alarm timeout */
75         if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
76                 usage4 (_("Cannot catch SIGALRM"));
77         }
78         alarm (timeout_interval);
80         /* run the command */
82         if (verbose)
83                 printf ("%s\n", comm);
85         child_process = spopen (comm);
87         if (child_process == NULL) {
88                 printf (_("Could not open pipe: %s\n"), comm);
89                 return STATE_UNKNOWN;
90         }
93         /* open STDERR  for spopen */
94         child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
95         if (child_stderr == NULL) {
96                 printf (_("Could not open stderr for %s\n"), SSH_COMMAND);
97         }
100         /* build up results from remote command in result_text */
101         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process))
102                 asprintf (&result_text, "%s%s", result_text, input_buffer);
104         /* WARNING if output found on stderr */
105         while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
106                 if (skip_lines > 0) {
107                         if (input_buffer[strlen(input_buffer)-1] == '\n') {
108                                 skip_lines--;
109                         }
110                 } else {
111                         printf ("%s", input_buffer);
112                         result = STATE_WARNING;
113                 }
114         }
115         (void) fclose (child_stderr);
116         if (result == STATE_WARNING)
117                 return result;
120         /* close the pipe */
121         result = spclose (child_process);
124         /* process output */
125         if (passive) {
127                 if (!(fp = fopen (outputfile, "a"))) {
128                         printf (_("SSH WARNING: could not open %s\n"), outputfile);
129                         exit (STATE_UNKNOWN);
130                 }
132                 local_time = time (NULL);
133                 commands = 0;
134                 while (result_text && strlen(result_text) > 0) {
135                         status_text = strstr (result_text, "STATUS CODE: ");
136                         if (status_text == NULL) {
137                                 printf ("%s", result_text);
138                                 return result;
139                         }
140                         asprintf (&output, "%s", result_text);
141                         result_text = strnl (status_text);
142                         eol = strpbrk (output, "\r\n");
143                         if (eol != NULL)
144                                 eol[0] = 0;
145                         if (service[commands] && status_text
146                                         && sscanf (status_text, "STATUS CODE: %d", &cresult) == 1) {
147                                 fprintf (fp, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n",
148                                                                  (int) local_time, host_shortname, service[commands++], cresult,
149                                                                  output);
150                         }
151                 }
153         }
156         /* print the first line from the remote command */
157         else {
158                 eol = strpbrk (result_text, "\r\n");
159                 if (eol)
160                         eol[0] = 0;
161                 printf ("%s\n", result_text);
162         }
165         /* return error status from remote command */   
166         return result;
169 /* process command-line arguments */
170 int
171 process_arguments (int argc, char **argv)
173         int c;
174         char *p1, *p2;
176         int option = 0;
177         static struct option longopts[] = {
178                 {"version", no_argument, 0, 'V'},
179                 {"help", no_argument, 0, 'h'},
180                 {"verbose", no_argument, 0, 'v'},
181                 {"fork", no_argument, 0, 'f'},
182                 {"timeout", required_argument, 0, 't'},
183                 {"host", required_argument, 0, 'H'},
184                 {"port", required_argument,0,'p'},
185                 {"output", required_argument, 0, 'O'},
186                 {"name", required_argument, 0, 'n'},
187                 {"services", required_argument, 0, 's'},
188                 {"identity", required_argument, 0, 'i'},
189                 {"user", required_argument, 0, 'u'},
190                 {"logname", required_argument, 0, 'l'},
191                 {"command", required_argument, 0, 'C'},
192                 {"skip", required_argument, 0, 'S'},
193                 {"proto1", no_argument, 0, '1'},
194                 {"proto2", no_argument, 0, '2'},
195                 {"use-ipv4", no_argument, 0, '4'},
196                 {"use-ipv6", no_argument, 0, '6'},
197                 {0, 0, 0, 0}
198         };
200         if (argc < 2)
201                 return ERROR;
203         for (c = 1; c < argc; c++)
204                 if (strcmp ("-to", argv[c]) == 0)
205                         strcpy (argv[c], "-t");
207         while (1) {
208                 c = getopt_long (argc, argv, "Vvh1246ft:H:O:p:i:u:l:C:S:n:s:", longopts,
209                                                                          &option);
211                 if (c == -1 || c == EOF)
212                         break;
214                 switch (c) {
215                 case '?':                                                                       /* help */
216                         usage2 (_("Unknown argument"), optarg);
217                 case 'V':                                                                       /* version */
218                         print_revision (progname, revision);
219                         exit (STATE_OK);
220                 case 'h':                                                                       /* help */
221                         print_help ();
222                         exit (STATE_OK);
223                 case 'v':                                                                       /* help */
224                         verbose = TRUE;
225                         break;
226                 case 't':                                                                       /* timeout period */
227                         if (!is_integer (optarg))
228                                 usage2 (_("Timeout interval must be a positive integer"), optarg);
229                         else
230                                 timeout_interval = atoi (optarg);
231                         break;
232                 case 'H':                                                                       /* host */
233                         if (!is_host (optarg))
234                                 usage2 (_("Invalid hostname/address"), optarg);
235                         hostname = optarg;
236                         break;
237                 case 'p': /* port number */
238                         if (!is_integer (optarg))
239                                 usage2 (_("Port must be a positive integer"), optarg);
240                         asprintf (&comm,"%s -p %s", comm, optarg);
241                         break;
242                 case 'O':                                                                       /* output file */
243                         outputfile = optarg;
244                         passive = TRUE;
245                         break;
246                 case 's':                                                                       /* description of service to check */
247                         service = realloc (service, (++services) * sizeof(char *));
248                         p1 = optarg;
249                         while ((p2 = index (p1, ':'))) {
250                                 *p2 = '\0';
251                                 asprintf (&service[services-1], "%s", p1);
252                                 service = realloc (service, (++services) * sizeof(char *));
253                                 p1 = p2 + 1;
254                         }
255                         asprintf (&service[services-1], "%s", p1);
256                         break;
257                 case 'n':                                                                       /* short name of host in nagios configuration */
258                         host_shortname = optarg;
259                         break;
260                 case 'u':
261                         c = 'l';
262                 case 'l':                                                                       /* login name */
263                 case 'i':                                                                       /* identity */
264                         asprintf (&comm, "%s -%c %s", comm, c, optarg);
265                         break;
266                 case '1':                                                                       /* Pass these switches directly to ssh */
267                 case '2':                                                                       /* 1 to force version 1, 2 to force version 2 */
268                 case '4':                                                                       /* -4 for IPv4 */
269                 case '6':                                                               /* -6 for IPv6 */
270                 case 'f':                                                                       /* fork to background */
271                         asprintf (&comm, "%s -%c", comm, c);
272                         break;
273                 case 'C':                                                                       /* Command for remote machine */
274                         commands++;
275                         if (commands > 1)
276                                 asprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
277                         asprintf (&remotecmd, "%s%s", remotecmd, optarg);
278                         break;
279                 case 'S':                                                                       /* Skip n lines in the output to ignore system banner */
280                         if (!is_integer (optarg))
281                                 usage2 (_("skip lines must be an integer"), optarg);
282                         else
283                                 skip_lines = atoi (optarg);
284                         break;
285                 }
286         }
288         c = optind;
289         if (hostname == NULL) {
290                 if (c <= argc) {
291                         die (STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname);
292                 } else if (!is_host (argv[c]))
293                         die (STATE_UNKNOWN, "%s: %s %s\n", progname, _("Invalid hostname/address"), argv[c]);
294                 hostname = argv[c++];
295         }
297         if (strlen(remotecmd) == 0) {
298                 for (; c < argc; c++)
299                         if (strlen(remotecmd) > 0)
300                                 asprintf (&remotecmd, "%s %s", remotecmd, argv[c]);
301                         else
302                                 asprintf (&remotecmd, "%s", argv[c]);
303         }
305         if (commands > 1)
306                 asprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
308         if (remotecmd == NULL || strlen (remotecmd) <= 1)
309                 usage4 (_("No remotecmd"));
311         asprintf (&comm, "%s %s '%s'", comm, hostname, remotecmd);
313         return validate_arguments ();
318 int
319 validate_arguments (void)
321         if (remotecmd == NULL || hostname == NULL)
322                 return ERROR;
324         if (passive && commands != services)
325                 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname);
327         if (passive && host_shortname == NULL)
328                 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the nagios configs.\n"), progname);
330         return OK;
334 void
335 print_help (void)
337         print_revision (progname, revision);
339         printf ("Copyright (c) 1999 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
340         printf (COPYRIGHT, copyright, email);
342         printf (_("This plugin uses SSH to execute commands on a remote host\n\n"));
344         print_usage ();
346         printf (_(UT_HELP_VRSN));
348         printf (_(UT_HOST_PORT), 'p', "none");
350         printf (_(UT_IPv46));
352         printf (_("\
353  -1, --proto1\n\
354     tell ssh to use Protocol 1\n\
355  -2, --proto2\n\
356     tell ssh to use Protocol 2\n\
357  -S, --skiplines=n\n\
358     Ignore first n lines on STDERR (to suppress a logon banner)\n\
359  -f\n\
360     tells ssh to fork rather than create a tty\n"));
362         printf (_("\
363  -C, --command='COMMAND STRING'\n\
364     command to execute on the remote machine\n\
365  -l, --logname=USERNAME\n\
366     SSH user name on remote host [optional]\n\
367  -i, --identity=KEYFILE\n\
368     identity of an authorized key [optional]\n\
369  -O, --output=FILE\n\
370     external command file for nagios [optional]\n\
371  -s, --services=LIST\n\
372     list of nagios service names, separated by ':' [optional]\n\
373  -n, --name=NAME\n\
374     short name of host in nagios configuration [optional]\n"));
376         printf (_(UT_WARN_CRIT));
378         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
380         printf (_("\n\
381 The most common mode of use is to refer to a local identity file with\n\
382 the '-i' option. In this mode, the identity pair should have a null\n\
383 passphrase and the public key should be listed in the authorized_keys\n\
384 file of the remote host. Usually the key will be restricted to running\n\
385 only one command on the remote server. If the remote SSH server tracks\n\
386 invocation agruments, the one remote program may be an agent that can\n\
387 execute additional commands as proxy\n"));
389         printf (_("\n\
390 To use passive mode, provide multiple '-C' options, and provide\n\
391 all of -O, -s, and -n options (servicelist order must match '-C'\n\
392 options)\n"));
394         printf ("\n\
395 $ check_by_ssh -H localhost -n lh -s c1:c2:c3 \\\n\
396     -C uptime -C uptime -C uptime -O /tmp/foo\n\
397 $ cat /tmp/foo\n\
398 [1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c1;0; up 2 days...\n\
399 [1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c2;0; up 2 days...\n\
400 [1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c3;0; up 2 days...\n");
402         printf (_(UT_SUPPORT));
407 void
408 print_usage (void)
410         printf ("\n\
411 Usage: %s [-f46] [-t timeout] [-i identity] [-l user] -H <host> -C <command>\n\
412                   [-n name] [-s servicelist] [-O outputfile] [-p port]\n", progname);