Code

Bug from code-clean (Antony Simmonds - 846311)
[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  *****************************************************************************/
18  
19 const char *progname = "check_by_ssh";
20 const char *revision = "$Revision$";
21 const char *copyright = "2000-2003";
22 const char *email = "nagiosplug-devel@lists.sourceforge.net";
24 #include "common.h"
25 #include "netutils.h"
26 #include "utils.h"
27 #include "popen.h"
29 int process_arguments (int, char **);
30 int validate_arguments (void);
31 void print_help (void);
32 void print_usage (void);
34 int commands = 0;
35 int services = 0;
36 char *remotecmd = NULL;
37 char *comm = NULL;
38 char *hostname = NULL;
39 char *outputfile = NULL;
40 char *host_shortname = NULL;
41 char **service;
42 int passive = FALSE;
43 int verbose = FALSE;
45 int
46 main (int argc, char **argv)
47 {
49         char input_buffer[MAX_INPUT_BUFFER];
50         char *result_text;
51         char *status_text;
52         char *output;
53         char *eol = NULL;
54         int cresult;
55         int result = STATE_UNKNOWN;
56         time_t local_time;
57         FILE *fp = NULL;
59         remotecmd = strdup ("");
60         comm = strdup (SSH_COMMAND);
61         result_text = strdup ("");
63         setlocale (LC_ALL, "");
64         bindtextdomain (PACKAGE, LOCALEDIR);
65         textdomain (PACKAGE);
67         /* process arguments */
68         if (process_arguments (argc, argv) == ERROR)
69                 usage (_("Could not parse arguments\n"));
72         /* Set signal handling and alarm timeout */
73         if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
74                 printf (_("Cannot catch SIGALRM"));
75                 return STATE_UNKNOWN;
76         }
77         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 (_("Unable to open pipe: %s"), 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);
105         /* WARNING if output found on stderr */
106         if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
107                 printf ("%s\n", input_buffer);
108                 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process))
109                         printf ("%s\n", input_buffer);
110                 return STATE_WARNING;
111         }
112         (void) fclose (child_stderr);
115         /* close the pipe */
116         result = spclose (child_process);
119         /* process output */
120         if (passive) {
122                 if (!(fp = fopen (outputfile, "a"))) {
123                         printf (_("SSH WARNING: could not open %s\n"), outputfile);
124                         exit (STATE_UNKNOWN);
125                 }
127                 local_time = time (NULL);
128                 commands = 0;
129                 while (result_text && strlen(result_text) > 0) {
130                         status_text = strstr (result_text, "STATUS CODE: ");
131                         if (status_text == NULL) {
132                                 printf ("%s", result_text);
133                                 return result;
134                         }
135                         asprintf (&output, "%s", result_text);
136                         result_text = strnl (status_text);
137                         eol = strpbrk (output, "\r\n");
138                         if (eol != NULL)
139                                 eol[0] = 0;
140                         if (service[commands] && status_text
141                                         && sscanf (status_text, "STATUS CODE: %d", &cresult) == 1) {
142                                 fprintf (fp, _("[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n"),
143                                                                  (int) local_time, host_shortname, service[commands++], cresult,
144                                                                  output);
145                         }
146                 }
148         }
151         /* print the first line from the remote command */
152         else {
153                 eol = strpbrk (result_text, "\r\n");
154                 if (eol)
155                         eol[0] = 0;
156                 printf ("%s\n", result_text);
157         }
160         /* return error status from remote command */   
161         return result;
168 \f
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                 {"proto1", no_argument, 0, '1'},
193                 {"proto2", no_argument, 0, '2'},
194                 {"use-ipv4", no_argument, 0, '4'},
195                 {"use-ipv6", no_argument, 0, '6'},
196                 {0, 0, 0, 0}
197         };
199         if (argc < 2)
200                 return ERROR;
202         for (c = 1; c < argc; c++)
203                 if (strcmp ("-to", argv[c]) == 0)
204                         strcpy (argv[c], "-t");
206         while (1) {
207                 c = getopt_long (argc, argv, "Vvh1246ft:H:O:p:i:u:l:C:n:s:", longopts,
208                                                                          &option);
210                 if (c == -1 || c == EOF)
211                         break;
213                 switch (c) {
214                 case '?':                                                                       /* help */
215                         print_usage ();
216                         exit (STATE_UNKNOWN);
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 an integer"), optarg);
229                         else
230                                 timeout_interval = atoi (optarg);
231                         break;
232                 case 'H':                                                                       /* host */
233                         if (!is_host (optarg))
234                                 usage2 (_("invalid host name"), optarg);
235                         hostname = optarg;
236                         break;
237                 case 'p': /* port number */
238                         if (!is_integer (optarg))
239                                 usage2 (_("port must be an 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                 }
279         }
281         c = optind;
282         if (hostname == NULL) {
283                 if (c <= argc) {
284                         die (STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname);
285                 } else if (!is_host (argv[c]))
286                         die (STATE_UNKNOWN, _("%s: Invalid host name %s\n"), progname, argv[c]);
287                 hostname = argv[c++];
288         }
290         if (strlen(remotecmd) == 0) {
291                 for (; c < argc; c++)
292                         if (strlen(remotecmd) > 0)
293                                 asprintf (&remotecmd, "%s %s", remotecmd, argv[c]);
294                         else
295                                 asprintf (&remotecmd, "%s", argv[c]);
296         }
298         if (commands > 1)
299                 asprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
301         if (remotecmd == NULL || strlen (remotecmd) <= 1)
302                 usage (_("No remotecmd\n"));
304         asprintf (&comm, "%s %s '%s'", comm, hostname, remotecmd);
306         return validate_arguments ();
313 int
314 validate_arguments (void)
316         if (remotecmd == NULL || hostname == NULL)
317                 return ERROR;
319         if (passive && commands != services)
320                 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname);
322         if (passive && host_shortname == NULL)
323                 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the nagios configs.\n"), progname);
325         return OK;
332 \f
333 void
334 print_help (void)
336         print_revision (progname, revision);
338         printf (_("Copyright (c) 1999 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n"));
339         printf (_(COPYRIGHT), copyright, email);
341         printf (_("This plugin uses SSH to execute commands on a remote host\n\n"));
343         print_usage ();
345         printf (_(UT_HELP_VRSN));
347         printf (_(UT_HOST_PORT), 'p', "none");
349         printf (_(UT_IPv46));
351         printf (_("\
352  -1, --proto1\n\
353     tell ssh to use Protocol 1\n\
354  -2, --proto2\n\
355     tell ssh to use Protocol 2\n\
356  -f\n\
357     tells ssh to fork rather than create a tty\n"));
359         printf (_("\
360  -C, --command='COMMAND STRING'\n\
361     command to execute on the remote machine\n\
362  -l, --logname=USERNAME\n\
363     SSH user name on remote host [optional]\n\
364  -i, --identity=KEYFILE\n\
365     identity of an authorized key [optional]\n\
366  -O, --output=FILE\n\
367     external command file for nagios [optional]\n\
368  -s, --services=LIST\n\
369     list of nagios service names, separated by ':' [optional]\n\
370  -n, --name=NAME\n\
371     short name of host in nagios configuration [optional]\n"));
373         printf (_(UT_WARN_CRIT));
375         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
377         printf (_("\n\
378 The most common mode of use is to refer to a local identity file with\n\
379 the '-i' option. In this mode, the identity pair should have a null\n\
380 passphrase and the public key should be listed in the authorized_keys\n\
381 file of the remote host. Usually the key will be restricted to running\n\
382 only one command on the remote server. If the remote SSH server tracks\n\
383 invocation agruments, the one remote program may be an agent that can\n\
384 execute additional commands as proxy\n"));
386         printf (_("\n\
387 To use passive mode, provide multiple '-C' options, and provide\n\
388 all of -O, -s, and -n options (servicelist order must match '-C'\n\
389 options)\n"));
391         printf (_(UT_SUPPORT));
398 void
399 print_usage (void)
401         printf (_("\n\
402 Usage: %s [-f46] [-t timeout] [-i identity] [-l user] -H <host> \n\
403   -C <command> [-n name] [-s servicelist] [-O outputfile] [-p port]\n"),
404                 progname);
405         printf (_(UT_HLP_VRS), progname, progname);