~ubuntu-branches/ubuntu/precise/nagios-plugins/precise-proposed

« back to all changes in this revision

Viewing changes to plugins/check_by_ssh.c

  • Committer: Bazaar Package Importer
  • Author(s): Guido Trotter
  • Date: 2004-06-15 15:37:48 UTC
  • Revision ID: james.westby@ubuntu.com-20040615153748-pq7702qdzghqfcns
Tags: upstream-1.3.1.0
ImportĀ upstreamĀ versionĀ 1.3.1.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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: check_by_ssh.c,v 1.9 2003/01/29 06:15:32 kdebisschop Exp $
 
22
 *
 
23
 *****************************************************************************/
 
24
 
 
25
const char *progname = "check_by_ssh";
 
26
#define DESCRIPTION "Run checks on a remote system using ssh, wrapping the proper timeout around the ssh invocation."
 
27
#define AUTHOR "Karl DeBisschop"
 
28
#define EMAIL "karl@debisschop.net"
 
29
#define COPYRIGHTDATE "1999, 2000, 2001"
 
30
 
 
31
#include "config.h"
 
32
#include "common.h"
 
33
#include "popen.h"
 
34
#include "utils.h"
 
35
#include <time.h>
 
36
 
 
37
int process_arguments (int, char **);
 
38
int validate_arguments (void);
 
39
void print_help (const char *command_name);
 
40
void print_usage (void);
 
41
 
 
42
 
 
43
int commands = 0;
 
44
int services = 0;
 
45
char *remotecmd = "";
 
46
char *comm = SSH_COMMAND;
 
47
char *hostname = NULL;
 
48
char *outputfile = NULL;
 
49
char *host_shortname = NULL;
 
50
char **service;
 
51
int passive = FALSE;
 
52
int verbose = FALSE;
 
53
 
 
54
 
 
55
int
 
56
main (int argc, char **argv)
 
57
{
 
58
 
 
59
        char input_buffer[MAX_INPUT_BUFFER] = "";
 
60
        char *result_text = "";
 
61
        char *status_text;
 
62
        char *output = "";
 
63
        char *summary = "";
 
64
        char *eol = NULL;
 
65
        char *srvc_desc = NULL;
 
66
        int cresult;
 
67
        int result = STATE_UNKNOWN;
 
68
        time_t local_time;
 
69
        FILE *fp = NULL;
 
70
 
 
71
 
 
72
        /* process arguments */
 
73
        if (process_arguments (argc, argv) == ERROR)
 
74
                usage ("Could not parse arguments\n");
 
75
 
 
76
 
 
77
        /* Set signal handling and alarm timeout */
 
78
        if (signal (SIGALRM, popen_timeout_alarm_handler) == SIG_ERR) {
 
79
                printf ("Cannot catch SIGALRM");
 
80
                return STATE_UNKNOWN;
 
81
        }
 
82
        alarm (timeout_interval);
 
83
 
 
84
 
 
85
        /* run the command */
 
86
 
 
87
        if (verbose)
 
88
                printf ("%s\n", comm);
 
89
 
 
90
        child_process = spopen (comm);
 
91
 
 
92
        if (child_process == NULL) {
 
93
                printf ("Unable to open pipe: %s", comm);
 
94
                return STATE_UNKNOWN;
 
95
        }
 
96
 
 
97
 
 
98
        /* open STDERR  for spopen */
 
99
        child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
 
100
        if (child_stderr == NULL) {
 
101
                printf ("Could not open stderr for %s\n", SSH_COMMAND);
 
102
        }
 
103
 
 
104
 
 
105
        /* get results from remote command */
 
106
        while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process))
 
107
                asprintf (&result_text, "%s%s", result_text, input_buffer);
 
108
 
 
109
 
 
110
        /* WARNING if output found on stderr */
 
111
        if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr)) {
 
112
                printf ("%s\n", input_buffer);
 
113
                return STATE_WARNING;
 
114
        }
 
115
        (void) fclose (child_stderr);
 
116
 
 
117
 
 
118
        /* close the pipe */
 
119
        result = spclose (child_process);
 
120
 
 
121
 
 
122
        /* process output */
 
123
        if (passive) {
 
124
 
 
125
                if (!(fp = fopen (outputfile, "a"))) {
 
126
                        printf ("SSH WARNING: could not open %s\n", outputfile);
 
127
                        exit (STATE_UNKNOWN);
 
128
                }
 
129
 
 
130
                time (&local_time);
 
131
                commands = 0;
 
132
                while (result_text && strlen(result_text) > 0) {
 
133
                        status_text = (strstr (result_text, "STATUS CODE: "));
 
134
                        if (status_text == NULL) {
 
135
                                printf ("%s", result_text);
 
136
                                return result;
 
137
                        }
 
138
                        asprintf (&output, "%s", result_text);
 
139
                        result_text = strnl (status_text);
 
140
                        eol = strpbrk (output, "\r\n");
 
141
                        if (eol != NULL)
 
142
                                eol[0] = 0;
 
143
                        if (service[commands] && status_text
 
144
                                        && sscanf (status_text, "STATUS CODE: %d", &cresult) == 1) {
 
145
                                fprintf (fp, "[%d] PROCESS_SERVICE_CHECK_RESULT;%s;%s;%d;%s\n",
 
146
                                                                 (int) local_time, host_shortname, service[commands++], cresult,
 
147
                                                                 output);
 
148
                        }
 
149
                }
 
150
 
 
151
        }
 
152
 
 
153
        /* print the first line from the remote command */
 
154
        else {
 
155
                eol = strpbrk (result_text, "\r\n");
 
156
                if (eol)
 
157
                        eol[0] = 0;
 
158
                printf ("%s\n", result_text);
 
159
        }
 
160
 
 
161
        /* return error status from remote command */
 
162
        return result;
 
163
}
 
164
 
 
165
 
 
166
 
 
167
 
 
168
 
 
169
/* process command-line arguments */
 
170
int
 
171
process_arguments (int argc, char **argv)
 
172
{
 
173
        int c, i;
 
174
        char *p1, *p2;
 
175
        size_t len;
 
176
 
 
177
#ifdef HAVE_GETOPT_H
 
178
        int option_index = 0;
 
179
        static struct option long_options[] = {
 
180
                {"version", no_argument, 0, 'V'},
 
181
                {"help", no_argument, 0, 'h'},
 
182
                {"verbose", no_argument, 0, 'v'},
 
183
                {"fork", no_argument, 0, 'f'},
 
184
                {"timeout", required_argument, 0, 't'},
 
185
                {"host", required_argument, 0, 'H'},
 
186
                {"port", required_argument,0,'p'},
 
187
                {"output", required_argument, 0, 'O'},
 
188
                {"name", required_argument, 0, 'n'},
 
189
                {"services", required_argument, 0, 's'},
 
190
                {"identity", required_argument, 0, 'i'},
 
191
                {"user", required_argument, 0, 'u'},
 
192
                {"logname", required_argument, 0, 'l'},
 
193
                {"command", required_argument, 0, 'C'},
 
194
                {"use-ipv4", no_argument, 0, '4'},
 
195
                {"use-ipv6", no_argument, 0, '6'},
 
196
                {0, 0, 0, 0}
 
197
        };
 
198
#endif
 
199
 
 
200
        if (argc < 2)
 
201
                return ERROR;
 
202
 
 
203
        for (c = 1; c < argc; c++)
 
204
                if (strcmp ("-to", argv[c]) == 0)
 
205
                        strcpy (argv[c], "-t");
 
206
 
 
207
        while (1) {
 
208
#ifdef HAVE_GETOPT_H
 
209
                c =
 
210
                        getopt_long (argc, argv, "Vvh46ft:H:O:p:i:u:l:C:n:s:", long_options,
 
211
                                                                         &option_index);
 
212
#else
 
213
                c = getopt (argc, argv, "Vvh46ft:H:O:p:i:u:l:C:n:s:");
 
214
#endif
 
215
 
 
216
                if (c == -1 || c == EOF)
 
217
                        break;
 
218
 
 
219
                switch (c) {
 
220
                case '?':                                                                       /* help */
 
221
                        print_usage ();
 
222
                        exit (STATE_UNKNOWN);
 
223
                case 'V':                                                                       /* version */
 
224
                        print_revision (progname, "$Revision: 1.9 $");
 
225
                        exit (STATE_OK);
 
226
                case 'h':                                                                       /* help */
 
227
                        print_help (progname);
 
228
                        exit (STATE_OK);
 
229
                case 'v':                                                                       /* help */
 
230
                        verbose = TRUE;
 
231
                        break;
 
232
                case 't':                                                                       /* timeout period */
 
233
                        if (!is_integer (optarg))
 
234
                                usage2 ("timeout interval must be an integer", optarg);
 
235
                        timeout_interval = atoi (optarg);
 
236
                        break;
 
237
                case 'H':                                                                       /* host */
 
238
                        if (!is_host (optarg))
 
239
                                usage2 ("invalid host name", optarg);
 
240
                        hostname = optarg;
 
241
                        break;
 
242
                case 'p': /* port number */
 
243
                        if (!is_integer (optarg))
 
244
                                usage2 ("port must be an integer", optarg);
 
245
                        asprintf (&comm,"%s -p %s", comm, optarg);
 
246
                        break;
 
247
                case 'O':                                                                       /* output file */
 
248
                        outputfile = optarg;
 
249
                        passive = TRUE;
 
250
                        break;
 
251
                case 's':                                                                       /* description of service to check */
 
252
                        service = realloc (service, (++services) * sizeof(char *));
 
253
                        p1 = optarg;
 
254
                        while (p2 = index (p1, ':')) {
 
255
                                *p2 = '\0';
 
256
                                asprintf (&service[services-1], "%s", p1);
 
257
                                service = realloc (service, (++services) * sizeof(char *));
 
258
                                p1 = p2 + 1;
 
259
                        }
 
260
                        asprintf (&service[services-1], "%s", p1);
 
261
                        break;
 
262
                case 'n':                                                                       /* short name of host in nagios configuration */
 
263
                        host_shortname = optarg;
 
264
                        break;
 
265
                case 'u':
 
266
                        c = 'l';
 
267
                case 'l':                                                                       /* login name */
 
268
                case 'i':                                                                       /* identity */
 
269
                        asprintf (&comm, "%s -%c %s", comm, c, optarg);
 
270
                        break;
 
271
                case '4':                                                                       /* Pass these switches directly to ssh */
 
272
                case '6':                                                               /* -4 for IPv4, -6 for IPv6 */
 
273
                case 'f':                                                                       /* fork to background */
 
274
                        asprintf (&comm, "%s -%c", comm, c);
 
275
                        break;
 
276
                case 'C':                                                                       /* Command for remote machine */
 
277
                        commands++;
 
278
                        if (commands > 1)
 
279
                                asprintf (&remotecmd, "%s;echo STATUS CODE: $?;", remotecmd);
 
280
                        asprintf (&remotecmd, "%s%s", remotecmd, optarg);
 
281
                }
 
282
        }
 
283
 
 
284
        c = optind;
 
285
        if (hostname == NULL) {
 
286
                if (c <= argc) {
 
287
                        terminate (STATE_UNKNOWN, "%s: You must provide a host name\n", progname);
 
288
                } else if (!is_host (argv[c]))
 
289
                        terminate (STATE_UNKNOWN, "%s: Invalid host name %s\n", progname, argv[c]);
 
290
                hostname = argv[c++];
 
291
        }
 
292
 
 
293
        if (strlen(remotecmd) == 0) {
 
294
                for (; c < argc; c++)
 
295
                        if (strlen(remotecmd) > 0)
 
296
                                asprintf (&remotecmd, "%s %s", remotecmd, argv[c]);
 
297
                        else
 
298
                                asprintf (&remotecmd, "%s", argv[c]);
 
299
        }
 
300
 
 
301
        if (commands > 1)
 
302
                remotecmd = strscat (remotecmd, ";echo STATUS CODE: $?;");
 
303
 
 
304
        if (remotecmd == NULL || strlen (remotecmd) <= 1)
 
305
                usage ("No remotecmd\n");
 
306
 
 
307
        asprintf (&comm, "%s %s '%s'", comm, hostname, remotecmd);
 
308
 
 
309
        return validate_arguments ();
 
310
}
 
311
 
 
312
 
 
313
 
 
314
 
 
315
 
 
316
int
 
317
validate_arguments (void)
 
318
{
 
319
        if (remotecmd == NULL || hostname == NULL)
 
320
                return ERROR;
 
321
 
 
322
        if (passive && commands != services)
 
323
                terminate (STATE_UNKNOWN, "%s: In passive mode, you must provide a service name for each command.\n", progname);
 
324
 
 
325
        if (passive && host_shortname == NULL)
 
326
                terminate (STATE_UNKNOWN, "%s: In passive mode, you must provide the host short name from the nagios configs.\n", progname);
 
327
 
 
328
        return OK;
 
329
}
 
330
 
 
331
 
 
332
 
 
333
 
 
334
 
 
335
void
 
336
print_help (const char *cmd)
 
337
{
 
338
        print_revision (cmd, "$Revision: 1.9 $");
 
339
 
 
340
        printf
 
341
                ("Copyright (c) 1999    Karl DeBisschop (kdebisschop@alum.mit.edu)\n\n"
 
342
                 "This plugin will execute a command on a remote host using SSH\n\n");
 
343
 
 
344
        print_usage ();
 
345
 
 
346
        printf
 
347
                ("\nOptions:\n"
 
348
                 "-H, --hostname=HOST\n"
 
349
                 "   name or IP address of remote host\n"
 
350
                 "-C, --command='COMMAND STRING'\n"
 
351
                 "   command to execute on the remote machine\n"
 
352
                 "-f tells ssh to fork rather than create a tty\n"
 
353
                 "-t, --timeout=INTEGER\n"
 
354
                 "   specify timeout (default: %d seconds) [optional]\n"
 
355
                 "-p, --port=PORT\n"
 
356
                 "   port to connect to on remote system [optional]\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"
 
367
                 "-4, --use-ipv4\n"
 
368
                 "   tell ssh to use IPv4\n"
 
369
                 "-6, --use-ipv6\n"
 
370
                 "   tell ssh to use IPv6\n"
 
371
                 "\n"
 
372
                 "The most common mode of use is to refer to a local identity file with\n"
 
373
                 "the '-i' option. In this mode, the identity pair should have a null\n"
 
374
                 "passphrase and the public key should be listed in the authorized_keys\n"
 
375
                 "file of the remote host. Usually the key will be restricted to running\n"
 
376
                 "only one command on the remote server. If the remote SSH server tracks\n"
 
377
                 "invocation agruments, the one remote program may be an agent that can\n"
 
378
                 "execute additional commands as proxy\n"
 
379
                 "\n"
 
380
                 "To use passive mode, provide multiple '-C' options, and provide\n"
 
381
                 "all of -O, -s, and -n options (servicelist order must match '-C'\n"
 
382
                 "options)\n", DEFAULT_SOCKET_TIMEOUT);
 
383
}
 
384
 
 
385
 
 
386
 
 
387
 
 
388
 
 
389
void
 
390
print_usage (void)
 
391
{
 
392
        printf
 
393
                ("Usage:\n"
 
394
                 "check_by_ssh [-f46] [-t timeout] [-i identity] [-l user] -H <host> -C <command>\n"
 
395
                 "             [-n name] [-s servicelist] [-O outputfile] [-p port]\n"
 
396
                 "check_by_ssh  -V prints version info\n"
 
397
                 "check_by_ssh  -h prints more detailed help\n");
 
398
}