Code

starting the BIG locale update ;-)
[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-2006";
24 const char *email = "nagiosplug-devel@lists.sourceforge.net";
26 #include "common.h"
27 #include "netutils.h"
28 #include "utils.h"
29 #include "runcmd.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 = 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 *status_text;
53         int cresult;
54         int result = STATE_UNKNOWN;
55         int i;
56         time_t local_time;
57         FILE *fp = NULL;
58         struct output chld_out, chld_err;
60         remotecmd = "";
61         comm = strdup (SSH_COMMAND);
63         setlocale (LC_ALL, "");
64         bindtextdomain (PACKAGE, LOCALEDIR);
65         textdomain (PACKAGE);
67         /* process arguments */
68         if (process_arguments (argc, argv) == ERROR)
69                 usage_va(_("Could not parse arguments"));
71         /* Set signal handling and alarm timeout */
72         if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
73                 usage_va(_("Cannot catch SIGALRM"));
74         }
75         alarm (timeout_interval);
77         /* run the command */
78         if (verbose)
79                 printf ("%s\n", comm);
81         result = np_runcmd(comm, &chld_out, &chld_err, 0);
82         /* UNKNOWN if output found on stderr */
83         if(chld_err.buflen) {
84                 printf(_("Remote command execution failed: %s\n"),
85                            chld_err.buflen ? chld_err.buf : _("Unknown error"));
86                 return STATE_UNKNOWN;
87         }
89         /* this is simple if we're not supposed to be passive.
90          * Wrap up quickly and keep the tricks below */
91         if(!passive) {
92                 printf ("%s\n", skip < chld_out.lines ? chld_out.line[skip] : chld_out.buf);
93                 return result;  /* return error status from remote command */
94         }
97         /*
98          * Passive mode
99          */
101         /* process output */
102         if (!(fp = fopen (outputfile, "a"))) {
103                 printf (_("SSH WARNING: could not open %s\n"), outputfile);
104                 exit (STATE_UNKNOWN);
105         }
107         local_time = time (NULL);
108         commands = 0;
109         for(i = skip; chld_out.line[i]; i++) {
110                 status_text = strstr (chld_out.line[i], "STATUS CODE: ");
111                 if (status_text == NULL) {
112                         printf ("%s", chld_out.line[i]);
113                         return result;
114                 }
115                 if (service[commands] && status_text
116                         && sscanf (status_text, "STATUS CODE: %d", &cresult) == 1)
117                 {
118                         fprintf (fp, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n",
119                                  (int) local_time, host_shortname, service[commands++],
120                                  cresult, chld_out.line[i]);
121                 }
122         }
123         
124         /* force an OK state */
125         return result;
128 /* process command-line arguments */
129 int
130 process_arguments (int argc, char **argv)
132         int c;
133         char *p1, *p2;
135         int option = 0;
136         static struct option longopts[] = {
137                 {"version", no_argument, 0, 'V'},
138                 {"help", no_argument, 0, 'h'},
139                 {"verbose", no_argument, 0, 'v'},
140                 {"fork", no_argument, 0, 'f'},
141                 {"timeout", required_argument, 0, 't'},
142                 {"host", required_argument, 0, 'H'},
143                 {"port", required_argument,0,'p'},
144                 {"output", required_argument, 0, 'O'},
145                 {"name", required_argument, 0, 'n'},
146                 {"services", required_argument, 0, 's'},
147                 {"identity", required_argument, 0, 'i'},
148                 {"user", required_argument, 0, 'u'},
149                 {"logname", required_argument, 0, 'l'},
150                 {"command", required_argument, 0, 'C'},
151                 {"skip", required_argument, 0, 'S'},
152                 {"proto1", no_argument, 0, '1'},
153                 {"proto2", no_argument, 0, '2'},
154                 {"use-ipv4", no_argument, 0, '4'},
155                 {"use-ipv6", no_argument, 0, '6'},
156                 {0, 0, 0, 0}
157         };
159         if (argc < 2)
160                 return ERROR;
162         for (c = 1; c < argc; c++)
163                 if (strcmp ("-to", argv[c]) == 0)
164                         strcpy (argv[c], "-t");
166         while (1) {
167                 c = getopt_long (argc, argv, "Vvh1246ft:H:O:p:i:u:l:C:S:n:s:", longopts,
168                                  &option);
170                 if (c == -1 || c == EOF)
171                         break;
173                 switch (c) {
174                 case 'V':                                                                       /* version */
175                         print_revision (progname, revision);
176                         exit (STATE_OK);
177                 case 'h':                                                                       /* help */
178                         print_help ();
179                         exit (STATE_OK);
180                 case 'v':                                                                       /* help */
181                         verbose = TRUE;
182                         break;
183                 case 't':                                                                       /* timeout period */
184                         if (!is_integer (optarg))
185                                 usage_va(_("Timeout interval must be a positive integer"));
186                         else
187                                 timeout_interval = atoi (optarg);
188                         break;
189                 case 'H':                                                                       /* host */
190                         host_or_die(optarg);
191                         hostname = optarg;
192                         break;
193                 case 'p': /* port number */
194                         if (!is_integer (optarg))
195                                 usage_va(_("Port must be a positive integer"));
196                         asprintf (&comm,"%s -p %s", comm, optarg);
197                         break;
198                 case 'O':                                                                       /* output file */
199                         outputfile = optarg;
200                         passive = TRUE;
201                         break;
202                 case 's':                                                                       /* description of service to check */
203                         p1 = optarg;
204                         service = realloc (service, (++services) * sizeof(char *));
205                         while ((p2 = index (p1, ':'))) {
206                                 *p2 = '\0';
207                                 service[services - 1] = p1;
208                                 service = realloc (service, (++services) * sizeof(char *));
209                                 p1 = p2 + 1;
210                         }
211                         service[services - 1] = p1;
212                         break;
213                 case 'n':                                                                       /* short name of host in nagios configuration */
214                         host_shortname = optarg;
215                         break;
217                 case 'u':
218                         c = 'l';
219                 case 'l':                                                                       /* login name */
220                 case 'i':                                                                       /* identity */
221                         asprintf (&comm, "%s -%c %s", comm, c, optarg);
222                         break;
224                 case '1':                                                                       /* Pass these switches directly to ssh */
225                 case '2':                                                                       /* 1 to force version 1, 2 to force version 2 */
226                 case '4':                                                                       /* -4 for IPv4 */
227                 case '6':                                                               /* -6 for IPv6 */
228                 case 'f':                                                                       /* fork to background */
229                         asprintf (&comm, "%s -%c", comm, c);
230                         break;
231                 case 'C':                                                                       /* Command for remote machine */
232                         commands++;
233                         if (commands > 1)
234                                 asprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
235                         asprintf (&remotecmd, "%s%s", remotecmd, optarg);
236                         break;
237                 case 'S':                                                                       /* Skip n lines in the output to ignore system banner */
238                         if (!is_integer (optarg))
239                                 usage_va(_("skip lines must be an integer"));
240                         else
241                                 skip = atoi (optarg);
242                         break;
243                 default:                                                                        /* help */
244                         usage_va(_("Unknown argument - %s"), optarg);
245                 }
246         }
248         c = optind;
249         if (hostname == NULL) {
250                 if (c <= argc) {
251                         die (STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname);
252                 }
253                 host_or_die(argv[c]);
254                 hostname = argv[c++];
255         }
257         if (strlen(remotecmd) == 0) {
258                 for (; c < argc; c++)
259                         if (strlen(remotecmd) > 0)
260                                 asprintf (&remotecmd, "%s %s", remotecmd, argv[c]);
261                         else
262                                 asprintf (&remotecmd, "%s", argv[c]);
263         }
265         if (commands > 1)
266                 asprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
268         if (remotecmd == NULL || strlen (remotecmd) <= 1)
269                 usage_va(_("No remotecmd"));
271         asprintf (&comm, "%s %s '%s'", comm, hostname, remotecmd);
273         return validate_arguments ();
278 int
279 validate_arguments (void)
281         if (remotecmd == NULL || hostname == NULL)
282                 return ERROR;
284         if (passive && commands != services)
285                 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname);
287         if (passive && host_shortname == NULL)
288                 die (STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the nagios configs.\n"), progname);
290         return OK;
294 void
295 print_help (void)
297         print_revision (progname, revision);
299         printf ("Copyright (c) 1999 Karl DeBisschop <kdebisschop@users.sourceforge.net>\n");
300         printf (COPYRIGHT, copyright, email);
302         printf (_("This plugin uses SSH to execute commands on a remote host"));
304   printf ("\n\n");
305   
306         print_usage ();
308         printf (_(UT_HELP_VRSN));
310         printf (_(UT_HOST_PORT), 'p', "none");
312         printf (_(UT_IPv46));
314   printf (" %s\n", "-1, --proto1");
315   printf ("    %s\n", _("tell ssh to use Protocol 1"));
316   printf (" %s\n", "-2, --proto2");
317   printf ("    %s\n", _("tell ssh to use Protocol 2"));
318   printf (" %s\n", "-S, --skiplines=n");
319   printf ("    %s\n", _("Ignore first n lines on STDERR (to suppress a logon banner)"));
320   printf (" %s\n", "-f");
321   printf ("    %s\n", _("tells ssh to fork rather than create a tty"));
322   printf (" %s\n","-C, --command='COMMAND STRING'");
323   printf ("    %s\n", _("command to execute on the remote machine"));
324   printf (" %s\n","-l, --logname=USERNAME");
325   printf ("    %s\n", _("SSH user name on remote host [optional]"));
326   printf (" %s\n","-i, --identity=KEYFILE");
327   printf ("    %s\n", _("identity of an authorized key [optional]"));
328   printf (" %s\n","-O, --output=FILE");
329   printf ("    %s\n", _("external command file for nagios [optional]"));
330   printf (" %s\n","-s, --services=LIST");
331   printf ("    %s\n", _("list of nagios service names, separated by ':' [optional]"));
332   printf (" %s\n","-n, --name=NAME");
333   printf ("    %s\n", _("short name of host in nagios configuration [optional]"));
334         printf (_(UT_WARN_CRIT));
335         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
336   printf (" %s\n", _("The most common mode of use is to refer to a local identity file with"));
337   printf (" %s\n", _("the '-i' option. In this mode, the identity pair should have a null"));
338   printf (" %s\n", _("passphrase and the public key should be listed in the authorized_keys"));
339   printf (" %s\n", _("file of the remote host. Usually the key will be restricted to running"));
340   printf (" %s\n", _("only one command on the remote server. If the remote SSH server tracks"));
341   printf (" %s\n", _("invocation arguments, the one remote program may be an agent that can"));
342   printf (" %s\n", _("execute additional commands as proxy"));
343   printf (" %s\n", _("To use passive mode, provide multiple '-C' options, and provide"));
344   printf (" %s\n", _("all of -O, -s, and -n options (servicelist order must match '-C'options)"));
345   printf ("\n");
346   printf ("%s\n", _("Examples:"));
347   printf (" %s\n", "$ check_by_ssh -H localhost -n lh -s c1:c2:c3 -C uptime -C uptime -C uptime -O /tmp/foo");
348   printf (" %s\n", "$ cat /tmp/foo");
349   printf (" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c1;0; up 2 days");
350   printf (" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c2;0; up 2 days");
351   printf (" %s\n", "[1080933700] PROCESS_SERVICE_CHECK_RESULT;flint;c3;0; up 2 days");
352         printf (_(UT_SUPPORT));
357 void
358 print_usage (void)
360         printf (_("Usage:"));
361   printf(" %s [-f46] [-t timeout] [-i identity] [-l user] -H <host> -C <command>",progname);
362   printf(" [-n name] [-s servicelist] [-O outputfile] [-p port]\n");