de106f229269a339766c2004f116c0bcfed86b3c
1 /******************************************************************************
2 *
3 * This file is part of the Nagios Plugins.
4 *
5 * Copyright (c) 1999, 2000, 2001 Karl DeBisschop <karl@debisschop.net>
6 *
7 * The Nagios Plugins are free software; you can redistribute them
8 * and/or modify them under the terms of the GNU General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 *
21 * $Id$
22 *
23 *****************************************************************************/
25 const char *progname = "check_by_ssh";
26 const char *revision = "$Revision$";
27 const char *copyright = "2000-2003";
28 const char *email = "nagiosplug-devel@lists.sourceforge.net";
30 #include "config.h"
31 #include "common.h"
32 #include "netutils.h"
33 #include "utils.h"
34 #include "popen.h"
36 int process_arguments (int, char **);
37 int validate_arguments (void);
38 void print_help (void);
39 void print_usage (void);
41 void
42 print_help (void)
43 {
44 print_revision (progname, revision);
46 printf (_(COPYRIGHT), copyright, email);
48 printf (_("This plugin uses SSH to execute commands on a remote host\n\n"));
50 print_usage ();
52 printf (_(HELP_VRSN));
54 printf (_(HOST_PORT), 'p', "none");
56 printf (_(IPv46));
58 printf (_("\
59 -1, --proto1\n\
60 tell ssh to use Protocol 1\n\
61 -2, --proto2\n\
62 tell ssh to use Protocol 2\n\
63 -f\n\
64 tells ssh to fork rather than create a tty\n"));
66 printf (_("\
67 -C, --command='COMMAND STRING'\n\
68 command to execute on the remote machine\n\
69 -l, --logname=USERNAME\n\
70 SSH user name on remote host [optional]\n\
71 -i, --identity=KEYFILE\n\
72 identity of an authorized key [optional]\n\
73 -O, --output=FILE\n\
74 external command file for nagios [optional]\n\
75 -s, --services=LIST\n\
76 list of nagios service names, separated by ':' [optional]\n\
77 -n, --name=NAME\n\
78 short name of host in nagios configuration [optional]\n"));
80 printf (_(WARN_CRIT_TO), DEFAULT_SOCKET_TIMEOUT);
82 printf (_("\n\
83 The most common mode of use is to refer to a local identity file with\n\
84 the '-i' option. In this mode, the identity pair should have a null\n\
85 passphrase and the public key should be listed in the authorized_keys\n\
86 file of the remote host. Usually the key will be restricted to running\n\
87 only one command on the remote server. If the remote SSH server tracks\n\
88 invocation agruments, the one remote program may be an agent that can\n\
89 execute additional commands as proxy\n"));
91 printf (_("\n\
92 To use passive mode, provide multiple '-C' options, and provide\n\
93 all of -O, -s, and -n options (servicelist order must match '-C'\n\
94 options)\n"));
95 }
101 void
102 print_usage (void)
103 {
104 printf (_("Usage:\n\
105 check_by_ssh [-f46] [-t timeout] [-i identity] [-l user] -H <host> -C <command>\n\
106 [-n name] [-s servicelist] [-O outputfile] [-p port]\n\
107 check_by_ssh -V prints version info\n\
108 check_by_ssh -h prints more detailed help\n"));
109 }
110 \f
112 int commands = 0;
113 int services = 0;
114 char *remotecmd = "";
115 char *comm = SSH_COMMAND;
116 char *hostname = NULL;
117 char *outputfile = NULL;
118 char *host_shortname = NULL;
119 char **service;
120 int passive = FALSE;
121 int verbose = FALSE;
124 int
125 main (int argc, char **argv)
126 {
128 char input_buffer[MAX_INPUT_BUFFER];
129 char *result_text = "";
130 char *status_text;
131 char *output = "";
132 char *eol = NULL;
133 int cresult;
134 int result = STATE_UNKNOWN;
135 time_t local_time;
136 FILE *fp = NULL;
139 /* process arguments */
140 if (process_arguments (argc, argv) == ERROR)
141 usage (_("Could not parse arguments\n"));
144 /* Set signal handling and alarm timeout */
145 if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
146 printf ("Cannot catch SIGALRM");
147 return STATE_UNKNOWN;
148 }
149 alarm (timeout_interval);
152 /* run the command */
154 if (verbose)
155 printf ("%s\n", comm);
157 child_process = spopen (comm);
159 if (child_process == NULL) {
160 printf (_("Unable to open pipe: %s"), comm);
161 return STATE_UNKNOWN;
162 }
165 /* open STDERR for spopen */
166 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
167 if (child_stderr == NULL) {
168 printf (_("Could not open stderr for %s\n"), SSH_COMMAND);
169 }
172 /* get results from remote command */
173 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process))
174 asprintf (&result_text, "%s%s", result_text, input_buffer);
177 /* WARNING if output found on stderr */
178 if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
179 printf ("%s\n", input_buffer);
180 return STATE_WARNING;
181 }
182 (void) fclose (child_stderr);
185 /* close the pipe */
186 result = spclose (child_process);
189 /* process output */
190 if (passive) {
192 if (!(fp = fopen (outputfile, "a"))) {
193 printf (_("SSH WARNING: could not open %s\n"), outputfile);
194 exit (STATE_UNKNOWN);
195 }
197 time (&local_time);
198 commands = 0;
199 while (result_text && strlen(result_text) > 0) {
200 status_text = strstr (result_text, _("STATUS CODE: "));
201 if (status_text == NULL) {
202 printf ("%s", result_text);
203 return result;
204 }
205 asprintf (&output, "%s", result_text);
206 result_text = strnl (status_text);
207 eol = strpbrk (output, "\r\n");
208 if (eol != NULL)
209 eol[0] = 0;
210 if (service[commands] && status_text
211 && sscanf (status_text, _("STATUS CODE: %d"), &cresult) == 1) {
212 fprintf (fp, _("[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n"),
213 (int) local_time, host_shortname, service[commands++], cresult,
214 output);
215 }
216 }
218 }
220 /* print the first line from the remote command */
221 else {
222 eol = strpbrk (result_text, "\r\n");
223 if (eol)
224 eol[0] = 0;
225 printf ("%s\n", result_text);
226 }
228 /* return error status from remote command */
229 return result;
230 }
236 /* process command-line arguments */
237 int
238 process_arguments (int argc, char **argv)
239 {
240 int c;
241 char *p1, *p2;
243 int option_index = 0;
244 static struct option long_options[] = {
245 {"version", no_argument, 0, 'V'},
246 {"help", no_argument, 0, 'h'},
247 {"verbose", no_argument, 0, 'v'},
248 {"fork", no_argument, 0, 'f'},
249 {"timeout", required_argument, 0, 't'},
250 {"host", required_argument, 0, 'H'},
251 {"port", required_argument,0,'p'},
252 {"output", required_argument, 0, 'O'},
253 {"name", required_argument, 0, 'n'},
254 {"services", required_argument, 0, 's'},
255 {"identity", required_argument, 0, 'i'},
256 {"user", required_argument, 0, 'u'},
257 {"logname", required_argument, 0, 'l'},
258 {"command", required_argument, 0, 'C'},
259 {"proto1", no_argument, 0, '1'},
260 {"proto2", no_argument, 0, '2'},
261 {"use-ipv4", no_argument, 0, '4'},
262 {"use-ipv6", no_argument, 0, '6'},
263 {0, 0, 0, 0}
264 };
266 if (argc < 2)
267 return ERROR;
269 for (c = 1; c < argc; c++)
270 if (strcmp ("-to", argv[c]) == 0)
271 strcpy (argv[c], "-t");
273 while (1) {
274 c = getopt_long (argc, argv, "Vvh1246ft:H:O:p:i:u:l:C:n:s:", long_options,
275 &option_index);
277 if (c == -1 || c == EOF)
278 break;
280 switch (c) {
281 case '?': /* help */
282 print_usage ();
283 exit (STATE_UNKNOWN);
284 case 'V': /* version */
285 print_revision (progname, "$Revision$");
286 exit (STATE_OK);
287 case 'h': /* help */
288 print_help ();
289 exit (STATE_OK);
290 case 'v': /* help */
291 verbose = TRUE;
292 break;
293 case 't': /* timeout period */
294 if (!is_integer (optarg))
295 usage2 (_("timeout interval must be an integer"), optarg);
296 timeout_interval = atoi (optarg);
297 break;
298 case 'H': /* host */
299 if (!is_host (optarg))
300 usage2 (_("invalid host name"), optarg);
301 hostname = optarg;
302 break;
303 case 'p': /* port number */
304 if (!is_integer (optarg))
305 usage2 (_("port must be an integer"), optarg);
306 asprintf (&comm,"%s -p %s", comm, optarg);
307 break;
308 case 'O': /* output file */
309 outputfile = optarg;
310 passive = TRUE;
311 break;
312 case 's': /* description of service to check */
313 service = realloc (service, (++services) * sizeof(char *));
314 p1 = optarg;
315 while ((p2 = index (p1, ':'))) {
316 *p2 = '\0';
317 asprintf (&service[services-1], "%s", p1);
318 service = realloc (service, (++services) * sizeof(char *));
319 p1 = p2 + 1;
320 }
321 asprintf (&service[services-1], "%s", p1);
322 break;
323 case 'n': /* short name of host in nagios configuration */
324 host_shortname = optarg;
325 break;
326 case 'u':
327 c = 'l';
328 case 'l': /* login name */
329 case 'i': /* identity */
330 asprintf (&comm, "%s -%c %s", comm, c, optarg);
331 break;
332 case '1': /* Pass these switches directly to ssh */
333 case '2': /* 1 to force version 1, 2 to force version 2 */
334 case '4': /* -4 for IPv4 */
335 case '6': /* -6 for IPv6 */
336 case 'f': /* fork to background */
337 asprintf (&comm, "%s -%c", comm, c);
338 break;
339 case 'C': /* Command for remote machine */
340 commands++;
341 if (commands > 1)
342 asprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
343 asprintf (&remotecmd, "%s%s", remotecmd, optarg);
344 }
345 }
347 c = optind;
348 if (hostname == NULL) {
349 if (c <= argc) {
350 terminate (STATE_UNKNOWN, _("%s: You must provide a host name\n"), progname);
351 } else if (!is_host (argv[c]))
352 terminate (STATE_UNKNOWN, _("%s: Invalid host name %s\n"), progname, argv[c]);
353 hostname = argv[c++];
354 }
356 if (strlen(remotecmd) == 0) {
357 for (; c < argc; c++)
358 if (strlen(remotecmd) > 0)
359 asprintf (&remotecmd, "%s %s", remotecmd, argv[c]);
360 else
361 asprintf (&remotecmd, "%s", argv[c]);
362 }
364 if (commands > 1)
365 remotecmd = strscat (remotecmd, ";echo STATUS CODE: $?;");
367 if (remotecmd == NULL || strlen (remotecmd) <= 1)
368 usage (_("No remotecmd\n"));
370 asprintf (&comm, "%s %s '%s'", comm, hostname, remotecmd);
372 return validate_arguments ();
373 }
379 int
380 validate_arguments (void)
381 {
382 if (remotecmd == NULL || hostname == NULL)
383 return ERROR;
385 if (passive && commands != services)
386 terminate (STATE_UNKNOWN, _("%s: In passive mode, you must provide a service name for each command.\n"), progname);
388 if (passive && host_shortname == NULL)
389 terminate (STATE_UNKNOWN, _("%s: In passive mode, you must provide the host short name from the nagios configs.\n"), progname);
391 return OK;
392 }