Prepare for the 2.2 release
[monitoring-plugins.git] / plugins / check_ssh.c
blob8ccbd5a7e9dc55f69dc73bea7348d29d6d949e0a
1 /*****************************************************************************
2 *
3 * Monitoring check_ssh plugin
4 *
5 * License: GPL
6 * Copyright (c) 2000-2007 Monitoring Plugins Development Team
7 *
8 * Description:
9 *
10 * This file contains the check_ssh plugin
12 * Try to connect to an SSH server at specified server and port
15 * This program is free software: you can redistribute it and/or modify
16 * it under the terms of the GNU General Public License as published by
17 * the Free Software Foundation, either version 3 of the License, or
18 * (at your option) any later version.
20 * This program is distributed in the hope that it will be useful,
21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23 * GNU General Public License for more details.
25 * You should have received a copy of the GNU General Public License
26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
29 *****************************************************************************/
31 const char *progname = "check_ssh";
32 const char *copyright = "2000-2007";
33 const char *email = "devel@monitoring-plugins.org";
35 #include "common.h"
36 #include "netutils.h"
37 #include "utils.h"
39 #ifndef MSG_DONTWAIT
40 #define MSG_DONTWAIT 0
41 #endif
43 #define SSH_DFL_PORT 22
44 #define BUFF_SZ 256
46 int port = -1;
47 char *server_name = NULL;
48 char *remote_version = NULL;
49 char *remote_protocol = NULL;
50 int verbose = FALSE;
52 int process_arguments (int, char **);
53 int validate_arguments (void);
54 void print_help (void);
55 void print_usage (void);
57 int ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol);
61 int
62 main (int argc, char **argv)
64 int result = STATE_UNKNOWN;
66 setlocale (LC_ALL, "");
67 bindtextdomain (PACKAGE, LOCALEDIR);
68 textdomain (PACKAGE);
70 /* Parse extra opts if any */
71 argv=np_extra_opts (&argc, argv, progname);
73 if (process_arguments (argc, argv) == ERROR)
74 usage4 (_("Could not parse arguments"));
76 /* initialize alarm signal handling */
77 signal (SIGALRM, socket_timeout_alarm_handler);
79 alarm (socket_timeout);
81 /* ssh_connect exits if error is found */
82 result = ssh_connect (server_name, port, remote_version, remote_protocol);
84 alarm (0);
86 return (result);
91 /* process command-line arguments */
92 int
93 process_arguments (int argc, char **argv)
95 int c;
97 int option = 0;
98 static struct option longopts[] = {
99 {"help", no_argument, 0, 'h'},
100 {"version", no_argument, 0, 'V'},
101 {"host", required_argument, 0, 'H'}, /* backward compatibility */
102 {"hostname", required_argument, 0, 'H'},
103 {"port", required_argument, 0, 'p'},
104 {"use-ipv4", no_argument, 0, '4'},
105 {"use-ipv6", no_argument, 0, '6'},
106 {"timeout", required_argument, 0, 't'},
107 {"verbose", no_argument, 0, 'v'},
108 {"remote-version", required_argument, 0, 'r'},
109 {"remote-protcol", required_argument, 0, 'P'},
110 {0, 0, 0, 0}
113 if (argc < 2)
114 return ERROR;
116 for (c = 1; c < argc; c++)
117 if (strcmp ("-to", argv[c]) == 0)
118 strcpy (argv[c], "-t");
120 while (1) {
121 c = getopt_long (argc, argv, "+Vhv46t:r:H:p:P:", longopts, &option);
123 if (c == -1 || c == EOF)
124 break;
126 switch (c) {
127 case '?': /* help */
128 usage5 ();
129 case 'V': /* version */
130 print_revision (progname, NP_VERSION);
131 exit (STATE_UNKNOWN);
132 case 'h': /* help */
133 print_help ();
134 exit (STATE_UNKNOWN);
135 case 'v': /* verbose */
136 verbose = TRUE;
137 break;
138 case 't': /* timeout period */
139 if (!is_integer (optarg))
140 usage2 (_("Timeout interval must be a positive integer"), optarg);
141 else
142 socket_timeout = atoi (optarg);
143 break;
144 case '4':
145 address_family = AF_INET;
146 break;
147 case '6':
148 #ifdef USE_IPV6
149 address_family = AF_INET6;
150 #else
151 usage4 (_("IPv6 support not available"));
152 #endif
153 break;
154 case 'r': /* remote version */
155 remote_version = optarg;
156 break;
157 case 'P': /* remote version */
158 remote_protocol = optarg;
159 break;
160 case 'H': /* host */
161 if (is_host (optarg) == FALSE)
162 usage2 (_("Invalid hostname/address"), optarg);
163 server_name = optarg;
164 break;
165 case 'p': /* port */
166 if (is_intpos (optarg)) {
167 port = atoi (optarg);
169 else {
170 usage2 (_("Port number must be a positive integer"), optarg);
175 c = optind;
176 if (server_name == NULL && c < argc) {
177 if (is_host (argv[c])) {
178 server_name = argv[c++];
182 if (port == -1 && c < argc) {
183 if (is_intpos (argv[c])) {
184 port = atoi (argv[c++]);
186 else {
187 print_usage ();
188 exit (STATE_UNKNOWN);
192 return validate_arguments ();
196 validate_arguments (void)
198 if (server_name == NULL)
199 return ERROR;
200 if (port == -1) /* funky, but allows -p to override stray integer in args */
201 port = SSH_DFL_PORT;
202 return OK;
206 /************************************************************************
208 * Try to connect to SSH server at specified server and port
210 *-----------------------------------------------------------------------*/
214 ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol)
216 int sd;
217 int result;
218 char *output = NULL;
219 char *buffer = NULL;
220 char *ssh_proto = NULL;
221 char *ssh_server = NULL;
222 static char *rev_no = VERSION;
223 struct timeval tv;
224 double elapsed_time;
226 gettimeofday(&tv, NULL);
228 result = my_tcp_connect (haddr, hport, &sd);
230 if (result != STATE_OK)
231 return result;
233 output = (char *) malloc (BUFF_SZ + 1);
234 memset (output, 0, BUFF_SZ + 1);
235 recv (sd, output, BUFF_SZ, 0);
236 if (strncmp (output, "SSH", 3)) {
237 printf (_("Server answer: %s"), output);
238 close(sd);
239 exit (STATE_CRITICAL);
241 else {
242 strip (output);
243 if (verbose)
244 printf ("%s\n", output);
245 ssh_proto = output + 4;
246 ssh_server = ssh_proto + strspn (ssh_proto, "-0123456789. ");
247 ssh_proto[strspn (ssh_proto, "0123456789. ")] = 0;
249 xasprintf (&buffer, "SSH-%s-check_ssh_%s\r\n", ssh_proto, rev_no);
250 send (sd, buffer, strlen (buffer), MSG_DONTWAIT);
251 if (verbose)
252 printf ("%s\n", buffer);
254 if (remote_version && strcmp(remote_version, ssh_server)) {
255 printf
256 (_("SSH CRITICAL - %s (protocol %s) version mismatch, expected '%s'\n"),
257 ssh_server, ssh_proto, remote_version);
258 close(sd);
259 exit (STATE_CRITICAL);
262 if (remote_protocol && strcmp(remote_protocol, ssh_proto)) {
263 printf
264 (_("SSH CRITICAL - %s (protocol %s) protocol version mismatch, expected '%s'\n"),
265 ssh_server, ssh_proto, remote_protocol);
266 close(sd);
267 exit (STATE_CRITICAL);
270 elapsed_time = (double)deltime(tv) / 1.0e6;
272 printf
273 (_("SSH OK - %s (protocol %s) | %s\n"),
274 ssh_server, ssh_proto, fperfdata("time", elapsed_time, "s",
275 FALSE, 0, FALSE, 0, TRUE, 0, TRUE, (int)socket_timeout));
276 close(sd);
277 exit (STATE_OK);
283 void
284 print_help (void)
286 char *myport;
287 xasprintf (&myport, "%d", SSH_DFL_PORT);
289 print_revision (progname, NP_VERSION);
291 printf ("Copyright (c) 1999 Remi Paulmier <remi@sinfomic.fr>\n");
292 printf (COPYRIGHT, copyright, email);
294 printf ("%s\n", _("Try to connect to an SSH server at specified server and port"));
296 printf ("\n\n");
298 print_usage ();
300 printf (UT_HELP_VRSN);
301 printf (UT_EXTRA_OPTS);
303 printf (UT_HOST_PORT, 'p', myport);
305 printf (UT_IPv46);
307 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
309 printf (" %s\n", "-r, --remote-version=STRING");
310 printf (" %s\n", _("Alert if string doesn't match expected server version (ex: OpenSSH_3.9p1)"));
312 printf (" %s\n", "-P, --remote-protocol=STRING");
313 printf (" %s\n", _("Alert if protocol doesn't match expected protocol version (ex: 2.0)"));
315 printf (UT_VERBOSE);
317 printf (UT_SUPPORT);
322 void
323 print_usage (void)
325 printf ("%s\n", _("Usage:"));
326 printf ("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] <host>\n", progname);