Code

internationalization fixes
[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                         printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
217                         print_usage ();
218                         exit (STATE_UNKNOWN);
219                 case 'V':                                                                       /* version */
220                         print_revision (progname, revision);
221                         exit (STATE_OK);
222                 case 'h':                                                                       /* help */
223                         print_help ();
224                         exit (STATE_OK);
225                 case 'v':                                                                       /* help */
226                         verbose = TRUE;
227                         break;
228                 case 't':                                                                       /* timeout period */
229                         if (!is_integer (optarg))
230                                 usage2 (_("Timeout interval must be a positive integer"), optarg);
231                         else
232                                 timeout_interval = atoi (optarg);
233                         break;
234                 case 'H':                                                                       /* host */
235                         if (!is_host (optarg))
236                                 usage2 (_("Invalid hostname/address"), optarg);
237                         hostname = optarg;
238                         break;
239                 case 'p': /* port number */
240                         if (!is_integer (optarg))
241                                 usage2 (_("Port must be a positive integer"), optarg);
242                         asprintf (&comm,"%s -p %s", comm, optarg);
243                         break;
244                 case 'O':                                                                       /* output file */
245                         outputfile = optarg;
246                         passive = TRUE;
247                         break;
248                 case 's':                                                                       /* description of service to check */
249                         service = realloc (service, (++services) * sizeof(char *));
250                         p1 = optarg;
251                         while ((p2 = index (p1, ':'))) {
252                                 *p2 = '\0';
253                                 asprintf (&service[services-1], "%s", p1);
254                                 service = realloc (service, (++services) * sizeof(char *));
255                                 p1 = p2 + 1;
256                         }
257                         asprintf (&service[services-1], "%s", p1);
258                         break;
259                 case 'n':                                                                       /* short name of host in nagios configuration */
260                         host_shortname = optarg;
261                         break;
262                 case 'u':
263                         c = 'l';
264                 case 'l':                                                                       /* login name */
265                 case 'i':                                                                       /* identity */
266                         asprintf (&comm, "%s -%c %s", comm, c, optarg);
267                         break;
268                 case '1':                                                                       /* Pass these switches directly to ssh */
269                 case '2':                                                                       /* 1 to force version 1, 2 to force version 2 */
270                 case '4':                                                                       /* -4 for IPv4 */
271                 case '6':                                                               /* -6 for IPv6 */
272                 case 'f':                                                                       /* fork to background */
273                         asprintf (&comm, "%s -%c", comm, c);
274                         break;
275                 case 'C':                                                                       /* Command for remote machine */
276                         commands++;
277                         if (commands > 1)
278                                 asprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
279                         asprintf (&remotecmd, "%s%s", remotecmd, optarg);
280                         break;
281                 case 'S':                                                                       /* Skip n lines in the output to ignore system banner */
282                         if (!is_integer (optarg))
283                                 usage2 (_("skip lines must be an integer"), optarg);
284                         else
285                                 skip_lines = atoi (optarg);
286                         break;
287                 }
288         }
290         c = optind;
291         if (hostname == NULL) {
292                 if (c <= argc) {
293                         die (STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname);
294                 } else if (!is_host (argv[c]))
295                         die (STATE_UNKNOWN, "%s: %s %s\n", progname, _("Invalid hostname/address"), argv[c]);
296                 hostname = argv[c++];
297         }
299         if (strlen(remotecmd) == 0) {
300                 for (; c < argc; c++)
301                         if (strlen(remotecmd) > 0)
302                                 asprintf (&remotecmd, "%s %s", remotecmd, argv[c]);
303                         else
304                                 asprintf (&remotecmd, "%s", argv[c]);
305         }
307         if (commands > 1)
308                 asprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
310         if (remotecmd == NULL || strlen (remotecmd) <= 1)
311                 usage4 (_("No remotecmd"));
313         asprintf (&comm, "%s %s '%s'", comm, hostname, remotecmd);
315         return validate_arguments ();
320 int
321 validate_arguments (void)
323         if (remotecmd == NULL || hostname == NULL)
324                 return ERROR;
326         if (passive && commands != services)
327                 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname);
329         if (passive && host_shortname == NULL)
330                 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the nagios configs.\n"), progname);
332         return OK;
336 void
337 print_help (void)
339         print_revision (progname, revision);
341         printf (_("Copyright (c) 1999 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n"));
342         printf (_(COPYRIGHT), copyright, email);
344         printf (_("This plugin uses SSH to execute commands on a remote host\n\n"));
346         print_usage ();
348         printf (_(UT_HELP_VRSN));
350         printf (_(UT_HOST_PORT), 'p', "none");
352         printf (_(UT_IPv46));
354         printf (_("\
355  -1, --proto1\n\
356     tell ssh to use Protocol 1\n\
357  -2, --proto2\n\
358     tell ssh to use Protocol 2\n\
359  -S, --skiplines=n\n\
360     Ignore first n lines on STDERR (to suppress a logon banner)\n\
361  -f\n\
362     tells ssh to fork rather than create a tty\n"));
364         printf (_("\
365  -C, --command='COMMAND STRING'\n\
366     command to execute on the remote machine\n\
367  -l, --logname=USERNAME\n\
368     SSH user name on remote host [optional]\n\
369  -i, --identity=KEYFILE\n\
370     identity of an authorized key [optional]\n\
371  -O, --output=FILE\n\
372     external command file for nagios [optional]\n\
373  -s, --services=LIST\n\
374     list of nagios service names, separated by ':' [optional]\n\
375  -n, --name=NAME\n\
376     short name of host in nagios configuration [optional]\n"));
378         printf (_(UT_WARN_CRIT));
380         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
382         printf (_("\n\
383 The most common mode of use is to refer to a local identity file with\n\
384 the '-i' option. In this mode, the identity pair should have a null\n\
385 passphrase and the public key should be listed in the authorized_keys\n\
386 file of the remote host. Usually the key will be restricted to running\n\
387 only one command on the remote server. If the remote SSH server tracks\n\
388 invocation agruments, the one remote program may be an agent that can\n\
389 execute additional commands as proxy\n"));
391         printf (_("\n\
392 To use passive mode, provide multiple '-C' options, and provide\n\
393 all of -O, -s, and -n options (servicelist order must match '-C'\n\
394 options)\n"));
396         printf (_("\n\
397 $ check_by_ssh -H localhost -n lh -s c1:c2:c3 \\\n\
398     -C uptime -C uptime -C uptime -O /tmp/foo\n\
399 $ cat /tmp/foo\n\
400 [1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c1;0; up 2 days...\n\
401 [1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c2;0; up 2 days...\n\
402 [1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c3;0; up 2 days...\n"));
404         printf (_(UT_SUPPORT));
409 void
410 print_usage (void)
412         printf ("\n\
413 Usage: %s [-f46] [-t timeout] [-i identity] [-l user] -H <host> -C <command>\n\
414                   [-n name] [-s servicelist] [-O outputfile] [-p port]\n", progname);