Code

fix a variety of compiler warnings about qualifier discards and other pedantic stuff
[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;
49 \f
50 int
51 main (int argc, char **argv)
52 {
54         char input_buffer[MAX_INPUT_BUFFER];
55         char *result_text;
56         char *status_text;
57         char *output;
58         char *eol = NULL;
59         int cresult;
60         int result = STATE_UNKNOWN;
61         time_t local_time;
62         FILE *fp = NULL;
64         asprintf (&remotecmd, "%s", "");
65         asprintf (&comm, "%s", SSH_COMMAND);
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         /* get results from remote command */
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                 return STATE_WARNING;
109         }
110         (void) fclose (child_stderr);
113         /* close the pipe */
114         result = spclose (child_process);
117         /* process output */
118         if (passive) {
120                 if (!(fp = fopen (outputfile, "a"))) {
121                         printf (_("SSH WARNING: could not open %s\n"), outputfile);
122                         exit (STATE_UNKNOWN);
123                 }
125                 time (&local_time);
126                 commands = 0;
127                 while (result_text && strlen(result_text) > 0) {
128                         status_text = strstr (result_text, _("STATUS CODE: "));
129                         if (status_text == NULL) {
130                                 printf ("%s", result_text);
131                                 return result;
132                         }
133                         asprintf (&output, "%s", result_text);
134                         result_text = strnl (status_text);
135                         eol = strpbrk (output, "\r\n");
136                         if (eol != NULL)
137                                 eol[0] = 0;
138                         if (service[commands] && status_text
139                                         && sscanf (status_text, _("STATUS CODE: %d"), &cresult) == 1) {
140                                 fprintf (fp, _("[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n"),
141                                                                  (int) local_time, host_shortname, service[commands++], cresult,
142                                                                  output);
143                         }
144                 }
146         }
148         /* print the first line from the remote command */
149         else {
150                 eol = strpbrk (result_text, "\r\n");
151                 if (eol)
152                         eol[0] = 0;
153                 printf ("%s\n", result_text);
154         }
156         /* return error status from remote command */
157         return result;
164 \f
165 /* process command-line arguments */
166 int
167 process_arguments (int argc, char **argv)
169         int c;
170         char *p1, *p2;
172         int option_index = 0;
173         static struct option long_options[] = {
174                 {"version", no_argument, 0, 'V'},
175                 {"help", no_argument, 0, 'h'},
176                 {"verbose", no_argument, 0, 'v'},
177                 {"fork", no_argument, 0, 'f'},
178                 {"timeout", required_argument, 0, 't'},
179                 {"host", required_argument, 0, 'H'},
180                 {"port", required_argument,0,'p'},
181                 {"output", required_argument, 0, 'O'},
182                 {"name", required_argument, 0, 'n'},
183                 {"services", required_argument, 0, 's'},
184                 {"identity", required_argument, 0, 'i'},
185                 {"user", required_argument, 0, 'u'},
186                 {"logname", required_argument, 0, 'l'},
187                 {"command", required_argument, 0, 'C'},
188                 {"proto1", no_argument, 0, '1'},
189                 {"proto2", no_argument, 0, '2'},
190                 {"use-ipv4", no_argument, 0, '4'},
191                 {"use-ipv6", no_argument, 0, '6'},
192                 {0, 0, 0, 0}
193         };
195         if (argc < 2)
196                 return ERROR;
198         for (c = 1; c < argc; c++)
199                 if (strcmp ("-to", argv[c]) == 0)
200                         strcpy (argv[c], "-t");
202         while (1) {
203                 c = getopt_long (argc, argv, "Vvh1246ft:H:O:p:i:u:l:C:n:s:", long_options,
204                                                                          &option_index);
206                 if (c == -1 || c == EOF)
207                         break;
209                 switch (c) {
210                 case '?':                                                                       /* help */
211                         print_usage ();
212                         exit (STATE_UNKNOWN);
213                 case 'V':                                                                       /* version */
214                         print_revision (progname, "$Revision$");
215                         exit (STATE_OK);
216                 case 'h':                                                                       /* help */
217                         print_help ();
218                         exit (STATE_OK);
219                 case 'v':                                                                       /* help */
220                         verbose = TRUE;
221                         break;
222                 case 't':                                                                       /* timeout period */
223                         if (!is_integer (optarg))
224                                 usage2 (_("timeout interval must be an integer"), optarg);
225                         timeout_interval = atoi (optarg);
226                         break;
227                 case 'H':                                                                       /* host */
228                         if (!is_host (optarg))
229                                 usage2 (_("invalid host name"), optarg);
230                         hostname = optarg;
231                         break;
232                 case 'p': /* port number */
233                         if (!is_integer (optarg))
234                                 usage2 (_("port must be an integer"), optarg);
235                         asprintf (&comm,"%s -p %s", comm, optarg);
236                         break;
237                 case 'O':                                                                       /* output file */
238                         outputfile = optarg;
239                         passive = TRUE;
240                         break;
241                 case 's':                                                                       /* description of service to check */
242                         service = realloc (service, (++services) * sizeof(char *));
243                         p1 = optarg;
244                         while ((p2 = index (p1, ':'))) {
245                                 *p2 = '\0';
246                                 asprintf (&service[services-1], "%s", p1);
247                                 service = realloc (service, (++services) * sizeof(char *));
248                                 p1 = p2 + 1;
249                         }
250                         asprintf (&service[services-1], "%s", p1);
251                         break;
252                 case 'n':                                                                       /* short name of host in nagios configuration */
253                         host_shortname = optarg;
254                         break;
255                 case 'u':
256                         c = 'l';
257                 case 'l':                                                                       /* login name */
258                 case 'i':                                                                       /* identity */
259                         asprintf (&comm, "%s -%c %s", comm, c, optarg);
260                         break;
261                 case '1':                                                                       /* Pass these switches directly to ssh */
262                 case '2':                                                                       /* 1 to force version 1, 2 to force version 2 */
263                 case '4':                                                                       /* -4 for IPv4 */
264                 case '6':                                                               /* -6 for IPv6 */
265                 case 'f':                                                                       /* fork to background */
266                         asprintf (&comm, "%s -%c", comm, c);
267                         break;
268                 case 'C':                                                                       /* Command for remote machine */
269                         commands++;
270                         if (commands > 1)
271                                 asprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
272                         asprintf (&remotecmd, "%s%s", remotecmd, optarg);
273                 }
274         }
276         c = optind;
277         if (hostname == NULL) {
278                 if (c <= argc) {
279                         die (STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname);
280                 } else if (!is_host (argv[c]))
281                         die (STATE_UNKNOWN, _("%s: Invalid host name %s\n"), progname, argv[c]);
282                 hostname = argv[c++];
283         }
285         if (strlen(remotecmd) == 0) {
286                 for (; c < argc; c++)
287                         if (strlen(remotecmd) > 0)
288                                 asprintf (&remotecmd, "%s %s", remotecmd, argv[c]);
289                         else
290                                 asprintf (&remotecmd, "%s", argv[c]);
291         }
293         if (commands > 1)
294                 remotecmd = strscat (remotecmd, ";echo STATUS CODE: $?;");
296         if (remotecmd == NULL || strlen (remotecmd) <= 1)
297                 usage (_("No remotecmd\n"));
299         asprintf (&comm, "%s %s '%s'", comm, hostname, remotecmd);
301         return validate_arguments ();
308 int
309 validate_arguments (void)
311         if (remotecmd == NULL || hostname == NULL)
312                 return ERROR;
314         if (passive && commands != services)
315                 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname);
317         if (passive && host_shortname == NULL)
318                 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the nagios configs.\n"), progname);
320         return OK;
327 \f
328 void
329 print_help (void)
331         print_revision (progname, revision);
333         printf (_("Copyright (c) 1999 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n"));
334         printf (_(COPYRIGHT), copyright, email);
336         printf (_("This plugin uses SSH to execute commands on a remote host\n\n"));
338         print_usage ();
340         printf (_(UT_HELP_VRSN));
342         printf (_(UT_HOST_PORT), 'p', "none");
344         printf (_(UT_IPv46));
346         printf (_("\
347  -1, --proto1\n\
348     tell ssh to use Protocol 1\n\
349  -2, --proto2\n\
350     tell ssh to use Protocol 2\n\
351  -f\n\
352     tells ssh to fork rather than create a tty\n"));
354         printf (_("\
355  -C, --command='COMMAND STRING'\n\
356     command to execute on the remote machine\n\
357  -l, --logname=USERNAME\n\
358     SSH user name on remote host [optional]\n\
359  -i, --identity=KEYFILE\n\
360     identity of an authorized key [optional]\n\
361  -O, --output=FILE\n\
362     external command file for nagios [optional]\n\
363  -s, --services=LIST\n\
364     list of nagios service names, separated by ':' [optional]\n\
365  -n, --name=NAME\n\
366     short name of host in nagios configuration [optional]\n"));
368         printf (_(UT_WARN_CRIT));
370         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
372         printf (_("\n\
373 The most common mode of use is to refer to a local identity file with\n\
374 the '-i' option. In this mode, the identity pair should have a null\n\
375 passphrase and the public key should be listed in the authorized_keys\n\
376 file of the remote host. Usually the key will be restricted to running\n\
377 only one command on the remote server. If the remote SSH server tracks\n\
378 invocation agruments, the one remote program may be an agent that can\n\
379 execute additional commands as proxy\n"));
381         printf (_("\n\
382 To use passive mode, provide multiple '-C' options, and provide\n\
383 all of -O, -s, and -n options (servicelist order must match '-C'\n\
384 options)\n"));
391 void
392 print_usage (void)
394         printf (_("\n\
395 Usage: %s [-f46] [-t timeout] [-i identity] [-l user] -H <host> \n\
396   -C <command> [-n name] [-s servicelist] [-O outputfile] [-p port]\n"),
397                 progname);
398         printf (_(UT_HLP_VRS), progname, progname);