summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/check_ssh.c330
1 files changed, 149 insertions, 181 deletions
diff --git a/plugins/check_ssh.c b/plugins/check_ssh.c
index 8e29fa98..9f805db4 100644
--- a/plugins/check_ssh.c
+++ b/plugins/check_ssh.c
@@ -1,32 +1,32 @@
1/***************************************************************************** 1/*****************************************************************************
2* 2 *
3* Monitoring check_ssh plugin 3 * Monitoring check_ssh plugin
4* 4 *
5* License: GPL 5 * License: GPL
6* Copyright (c) 2000-2024 Monitoring Plugins Development Team 6 * Copyright (c) 2000-2024 Monitoring Plugins Development Team
7* 7 *
8* Description: 8 * Description:
9* 9 *
10* This file contains the check_ssh plugin 10 * This file contains the check_ssh plugin
11* 11 *
12* Try to connect to an SSH server at specified server and port 12 * Try to connect to an SSH server at specified server and port
13* 13 *
14* 14 *
15* This program is free software: you can redistribute it and/or modify 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 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 17 * the Free Software Foundation, either version 3 of the License, or
18* (at your option) any later version. 18 * (at your option) any later version.
19* 19 *
20* This program is distributed in the hope that it will be useful, 20 * This program is distributed in the hope that it will be useful,
21* but WITHOUT ANY WARRANTY; without even the implied warranty of 21 * but WITHOUT ANY WARRANTY; without even the implied warranty of
22* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 22 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
23* GNU General Public License for more details. 23 * GNU General Public License for more details.
24* 24 *
25* You should have received a copy of the GNU General Public License 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/>. 26 * along with this program. If not, see <http://www.gnu.org/licenses/>.
27* 27 *
28* 28 *
29*****************************************************************************/ 29 *****************************************************************************/
30 30
31const char *progname = "check_ssh"; 31const char *progname = "check_ssh";
32const char *copyright = "2000-2024"; 32const char *copyright = "2000-2024";
@@ -37,11 +37,11 @@ const char *email = "devel@monitoring-plugins.org";
37#include "utils.h" 37#include "utils.h"
38 38
39#ifndef MSG_DONTWAIT 39#ifndef MSG_DONTWAIT
40#define MSG_DONTWAIT 0 40# define MSG_DONTWAIT 0
41#endif 41#endif
42 42
43#define SSH_DFL_PORT 22 43#define SSH_DFL_PORT 22
44#define BUFF_SZ 256 44#define BUFF_SZ 256
45 45
46int port = -1; 46int port = -1;
47char *server_name = NULL; 47char *server_name = NULL;
@@ -49,96 +49,87 @@ char *remote_version = NULL;
49char *remote_protocol = NULL; 49char *remote_protocol = NULL;
50bool verbose = false; 50bool verbose = false;
51 51
52int process_arguments (int, char **); 52int process_arguments(int, char **);
53int validate_arguments (void); 53int validate_arguments(void);
54void print_help (void); 54void print_help(void);
55void print_usage (void); 55void print_usage(void);
56 56
57int ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol); 57int ssh_connect(char *haddr, int hport, char *remote_version, char *remote_protocol);
58 58
59 59int main(int argc, char **argv) {
60int
61main (int argc, char **argv)
62{
63 int result = STATE_UNKNOWN; 60 int result = STATE_UNKNOWN;
64 61
65 setlocale (LC_ALL, ""); 62 setlocale(LC_ALL, "");
66 bindtextdomain (PACKAGE, LOCALEDIR); 63 bindtextdomain(PACKAGE, LOCALEDIR);
67 textdomain (PACKAGE); 64 textdomain(PACKAGE);
68 65
69 /* Parse extra opts if any */ 66 /* Parse extra opts if any */
70 argv=np_extra_opts (&argc, argv, progname); 67 argv = np_extra_opts(&argc, argv, progname);
71 68
72 if (process_arguments (argc, argv) == ERROR) 69 if (process_arguments(argc, argv) == ERROR)
73 usage4 (_("Could not parse arguments")); 70 usage4(_("Could not parse arguments"));
74 71
75 /* initialize alarm signal handling */ 72 /* initialize alarm signal handling */
76 signal (SIGALRM, socket_timeout_alarm_handler); 73 signal(SIGALRM, socket_timeout_alarm_handler);
77 74
78 alarm (socket_timeout); 75 alarm(socket_timeout);
79 76
80 /* ssh_connect exits if error is found */ 77 /* ssh_connect exits if error is found */
81 result = ssh_connect (server_name, port, remote_version, remote_protocol); 78 result = ssh_connect(server_name, port, remote_version, remote_protocol);
82 79
83 alarm (0); 80 alarm(0);
84 81
85 return (result); 82 return (result);
86} 83}
87 84
88
89
90/* process command-line arguments */ 85/* process command-line arguments */
91int 86int process_arguments(int argc, char **argv) {
92process_arguments (int argc, char **argv)
93{
94 int c; 87 int c;
95 88
96 int option = 0; 89 int option = 0;
97 static struct option longopts[] = { 90 static struct option longopts[] = {{"help", no_argument, 0, 'h'},
98 {"help", no_argument, 0, 'h'}, 91 {"version", no_argument, 0, 'V'},
99 {"version", no_argument, 0, 'V'}, 92 {"host", required_argument, 0, 'H'}, /* backward compatibility */
100 {"host", required_argument, 0, 'H'}, /* backward compatibility */ 93 {"hostname", required_argument, 0, 'H'},
101 {"hostname", required_argument, 0, 'H'}, 94 {"port", required_argument, 0, 'p'},
102 {"port", required_argument, 0, 'p'}, 95 {"use-ipv4", no_argument, 0, '4'},
103 {"use-ipv4", no_argument, 0, '4'}, 96 {"use-ipv6", no_argument, 0, '6'},
104 {"use-ipv6", no_argument, 0, '6'}, 97 {"timeout", required_argument, 0, 't'},
105 {"timeout", required_argument, 0, 't'}, 98 {"verbose", no_argument, 0, 'v'},
106 {"verbose", no_argument, 0, 'v'}, 99 {"remote-version", required_argument, 0, 'r'},
107 {"remote-version", required_argument, 0, 'r'}, 100 {"remote-protocol", required_argument, 0, 'P'},
108 {"remote-protocol", required_argument, 0, 'P'}, 101 {0, 0, 0, 0}};
109 {0, 0, 0, 0}
110 };
111 102
112 if (argc < 2) 103 if (argc < 2)
113 return ERROR; 104 return ERROR;
114 105
115 for (c = 1; c < argc; c++) 106 for (c = 1; c < argc; c++)
116 if (strcmp ("-to", argv[c]) == 0) 107 if (strcmp("-to", argv[c]) == 0)
117 strcpy (argv[c], "-t"); 108 strcpy(argv[c], "-t");
118 109
119 while (1) { 110 while (1) {
120 c = getopt_long (argc, argv, "+Vhv46t:r:H:p:P:", longopts, &option); 111 c = getopt_long(argc, argv, "+Vhv46t:r:H:p:P:", longopts, &option);
121 112
122 if (c == -1 || c == EOF) 113 if (c == -1 || c == EOF)
123 break; 114 break;
124 115
125 switch (c) { 116 switch (c) {
126 case '?': /* help */ 117 case '?': /* help */
127 usage5 (); 118 usage5();
128 case 'V': /* version */ 119 case 'V': /* version */
129 print_revision (progname, NP_VERSION); 120 print_revision(progname, NP_VERSION);
130 exit (STATE_UNKNOWN); 121 exit(STATE_UNKNOWN);
131 case 'h': /* help */ 122 case 'h': /* help */
132 print_help (); 123 print_help();
133 exit (STATE_UNKNOWN); 124 exit(STATE_UNKNOWN);
134 case 'v': /* verbose */ 125 case 'v': /* verbose */
135 verbose = true; 126 verbose = true;
136 break; 127 break;
137 case 't': /* timeout period */ 128 case 't': /* timeout period */
138 if (!is_integer (optarg)) 129 if (!is_integer(optarg))
139 usage2 (_("Timeout interval must be a positive integer"), optarg); 130 usage2(_("Timeout interval must be a positive integer"), optarg);
140 else 131 else
141 socket_timeout = atoi (optarg); 132 socket_timeout = atoi(optarg);
142 break; 133 break;
143 case '4': 134 case '4':
144 address_family = AF_INET; 135 address_family = AF_INET;
@@ -147,71 +138,63 @@ process_arguments (int argc, char **argv)
147#ifdef USE_IPV6 138#ifdef USE_IPV6
148 address_family = AF_INET6; 139 address_family = AF_INET6;
149#else 140#else
150 usage4 (_("IPv6 support not available")); 141 usage4(_("IPv6 support not available"));
151#endif 142#endif
152 break; 143 break;
153 case 'r': /* remote version */ 144 case 'r': /* remote version */
154 remote_version = optarg; 145 remote_version = optarg;
155 break; 146 break;
156 case 'P': /* remote version */ 147 case 'P': /* remote version */
157 remote_protocol = optarg; 148 remote_protocol = optarg;
158 break; 149 break;
159 case 'H': /* host */ 150 case 'H': /* host */
160 if (!is_host (optarg)) 151 if (!is_host(optarg))
161 usage2 (_("Invalid hostname/address"), optarg); 152 usage2(_("Invalid hostname/address"), optarg);
162 server_name = optarg; 153 server_name = optarg;
163 break; 154 break;
164 case 'p': /* port */ 155 case 'p': /* port */
165 if (is_intpos (optarg)) { 156 if (is_intpos(optarg)) {
166 port = atoi (optarg); 157 port = atoi(optarg);
167 } 158 } else {
168 else { 159 usage2(_("Port number must be a positive integer"), optarg);
169 usage2 (_("Port number must be a positive integer"), optarg);
170 } 160 }
171 } 161 }
172 } 162 }
173 163
174 c = optind; 164 c = optind;
175 if (server_name == NULL && c < argc) { 165 if (server_name == NULL && c < argc) {
176 if (is_host (argv[c])) { 166 if (is_host(argv[c])) {
177 server_name = argv[c++]; 167 server_name = argv[c++];
178 } 168 }
179 } 169 }
180 170
181 if (port == -1 && c < argc) { 171 if (port == -1 && c < argc) {
182 if (is_intpos (argv[c])) { 172 if (is_intpos(argv[c])) {
183 port = atoi (argv[c++]); 173 port = atoi(argv[c++]);
184 } 174 } else {
185 else { 175 print_usage();
186 print_usage (); 176 exit(STATE_UNKNOWN);
187 exit (STATE_UNKNOWN);
188 } 177 }
189 } 178 }
190 179
191 return validate_arguments (); 180 return validate_arguments();
192} 181}
193 182
194int 183int validate_arguments(void) {
195validate_arguments (void)
196{
197 if (server_name == NULL) 184 if (server_name == NULL)
198 return ERROR; 185 return ERROR;
199 if (port == -1) /* funky, but allows -p to override stray integer in args */ 186 if (port == -1) /* funky, but allows -p to override stray integer in args */
200 port = SSH_DFL_PORT; 187 port = SSH_DFL_PORT;
201 return OK; 188 return OK;
202} 189}
203 190
204
205/************************************************************************ 191/************************************************************************
206* 192 *
207* Try to connect to SSH server at specified server and port 193 * Try to connect to SSH server at specified server and port
208* 194 *
209*-----------------------------------------------------------------------*/ 195 *-----------------------------------------------------------------------*/
210
211 196
212int 197int ssh_connect(char *haddr, int hport, char *remote_version, char *remote_protocol) {
213ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol)
214{
215 int sd; 198 int sd;
216 int result; 199 int result;
217 int len = 0; 200 int len = 0;
@@ -225,41 +208,41 @@ ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol
225 208
226 gettimeofday(&tv, NULL); 209 gettimeofday(&tv, NULL);
227 210
228 result = my_tcp_connect (haddr, hport, &sd); 211 result = my_tcp_connect(haddr, hport, &sd);
229 212
230 if (result != STATE_OK) 213 if (result != STATE_OK)
231 return result; 214 return result;
232 215
233 char *output = (char *) calloc (BUFF_SZ + 1, sizeof(char)); 216 char *output = (char *)calloc(BUFF_SZ + 1, sizeof(char));
234 217
235 ssize_t byte_offset = 0; 218 ssize_t byte_offset = 0;
236 219
237 while ((version_control_string == NULL) && (recv_ret = recv(sd, output+byte_offset, BUFF_SZ - byte_offset, 0) > 0)) { 220 while ((version_control_string == NULL) && (recv_ret = recv(sd, output + byte_offset, BUFF_SZ - byte_offset, 0) > 0)) {
238 221
239 if (strchr(output, '\n')) { /* we've got at least one full line, start parsing*/ 222 if (strchr(output, '\n')) { /* we've got at least one full line, start parsing*/
240 byte_offset = 0; 223 byte_offset = 0;
241 224
242 char *index = NULL; 225 char *index = NULL;
243 while ((index = strchr(output+byte_offset, '\n')) != NULL) { 226 while ((index = strchr(output + byte_offset, '\n')) != NULL) {
244 /*Partition the buffer so that this line is a separate string, 227 /*Partition the buffer so that this line is a separate string,
245 * by replacing the newline with NUL*/ 228 * by replacing the newline with NUL*/
246 output[(index - output)] = '\0'; 229 output[(index - output)] = '\0';
247 len = strlen(output + byte_offset); 230 len = strlen(output + byte_offset);
248 231
249 if ((len >= 4) && (strncmp (output+byte_offset, "SSH-", 4) == 0)) { 232 if ((len >= 4) && (strncmp(output + byte_offset, "SSH-", 4) == 0)) {
250 /*if the string starts with SSH-, this _should_ be a valid version control string*/ 233 /*if the string starts with SSH-, this _should_ be a valid version control string*/
251 version_control_string = output+byte_offset; 234 version_control_string = output + byte_offset;
252 break; 235 break;
253 } 236 }
254 237
255 /*the start of the next line (if one exists) will be after the current one (+ NUL)*/ 238 /*the start of the next line (if one exists) will be after the current one (+ NUL)*/
256 byte_offset += (len + 1); 239 byte_offset += (len + 1);
257 } 240 }
258 241
259 if(version_control_string == NULL) { 242 if (version_control_string == NULL) {
260 /* move unconsumed data to beginning of buffer, null rest */ 243 /* move unconsumed data to beginning of buffer, null rest */
261 memmove((void *)output, (void *)output+byte_offset+1, BUFF_SZ - len+1); 244 memmove((void *)output, (void *)output + byte_offset + 1, BUFF_SZ - len + 1);
262 memset(output+byte_offset+1, 0, BUFF_SZ-byte_offset+1); 245 memset(output + byte_offset + 1, 0, BUFF_SZ - byte_offset + 1);
263 246
264 /*start reading from end of current line chunk on next recv*/ 247 /*start reading from end of current line chunk on next recv*/
265 byte_offset = strlen(output); 248 byte_offset = strlen(output);
@@ -285,9 +268,9 @@ ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol
285 * SSH-protoversion-softwareversion SP comments CR LF" 268 * SSH-protoversion-softwareversion SP comments CR LF"
286 * - RFC 4253:4.2 269 * - RFC 4253:4.2
287 */ 270 */
288 strip (version_control_string); 271 strip(version_control_string);
289 if (verbose) 272 if (verbose)
290 printf ("%s\n", version_control_string); 273 printf("%s\n", version_control_string);
291 ssh_proto = version_control_string + 4; 274 ssh_proto = version_control_string + 4;
292 275
293 /* 276 /*
@@ -306,7 +289,7 @@ ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol
306 * "1.x" (e.g., "1.5" or "1.3")." 289 * "1.x" (e.g., "1.5" or "1.3")."
307 * - RFC 4253:5 290 * - RFC 4253:5
308 */ 291 */
309 ssh_server = ssh_proto + strspn (ssh_proto, "0123456789.") + 1; /* (+1 for the '-' separating protoversion from softwareversion) */ 292 ssh_server = ssh_proto + strspn(ssh_proto, "0123456789.") + 1; /* (+1 for the '-' separating protoversion from softwareversion) */
310 293
311 /* If there's a space in the version string, whatever's after the space is a comment 294 /* If there's a space in the version string, whatever's after the space is a comment
312 * (which is NOT part of the server name/version)*/ 295 * (which is NOT part of the server name/version)*/
@@ -316,86 +299,71 @@ ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol
316 } 299 }
317 if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) { 300 if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) {
318 printf(_("SSH CRITICAL - Invalid protocol version control string %s\n"), version_control_string); 301 printf(_("SSH CRITICAL - Invalid protocol version control string %s\n"), version_control_string);
319 exit (STATE_CRITICAL); 302 exit(STATE_CRITICAL);
320 } 303 }
321 ssh_proto[strspn (ssh_proto, "0123456789. ")] = 0; 304 ssh_proto[strspn(ssh_proto, "0123456789. ")] = 0;
322 305
323 xasprintf (&buffer, "SSH-%s-check_ssh_%s\r\n", ssh_proto, rev_no); 306 xasprintf(&buffer, "SSH-%s-check_ssh_%s\r\n", ssh_proto, rev_no);
324 send (sd, buffer, strlen (buffer), MSG_DONTWAIT); 307 send(sd, buffer, strlen(buffer), MSG_DONTWAIT);
325 if (verbose) 308 if (verbose)
326 printf ("%s\n", buffer); 309 printf("%s\n", buffer);
327 310
328 if (remote_version && strcmp(remote_version, ssh_server)) { 311 if (remote_version && strcmp(remote_version, ssh_server)) {
329 printf 312 printf(_("SSH CRITICAL - %s (protocol %s) version mismatch, expected '%s'\n"), ssh_server, ssh_proto, remote_version);
330 (_("SSH CRITICAL - %s (protocol %s) version mismatch, expected '%s'\n"),
331 ssh_server, ssh_proto, remote_version);
332 close(sd); 313 close(sd);
333 exit (STATE_CRITICAL); 314 exit(STATE_CRITICAL);
334 } 315 }
335 316
336 double elapsed_time = (double)deltime(tv) / 1.0e6; 317 double elapsed_time = (double)deltime(tv) / 1.0e6;
337 if (remote_protocol && strcmp(remote_protocol, ssh_proto)) { 318 if (remote_protocol && strcmp(remote_protocol, ssh_proto)) {
338 printf 319 printf(_("SSH CRITICAL - %s (protocol %s) protocol version mismatch, expected '%s' | %s\n"), ssh_server, ssh_proto, remote_protocol,
339 (_("SSH CRITICAL - %s (protocol %s) protocol version mismatch, expected '%s' | %s\n"), 320 fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, true, (int)socket_timeout));
340 ssh_server, ssh_proto, remote_protocol, fperfdata("time", elapsed_time, "s",
341 false, 0, false, 0, true, 0, true, (int)socket_timeout));
342 close(sd); 321 close(sd);
343 exit (STATE_CRITICAL); 322 exit(STATE_CRITICAL);
344 } 323 }
345 324
346 printf 325 printf(_("SSH OK - %s (protocol %s) | %s\n"), ssh_server, ssh_proto,
347 (_("SSH OK - %s (protocol %s) | %s\n"), 326 fperfdata("time", elapsed_time, "s", false, 0, false, 0, true, 0, true, (int)socket_timeout));
348 ssh_server, ssh_proto, fperfdata("time", elapsed_time, "s",
349 false, 0, false, 0, true, 0, true, (int)socket_timeout));
350 close(sd); 327 close(sd);
351 exit (STATE_OK); 328 exit(STATE_OK);
352} 329}
353 330
354 331void print_help(void) {
355
356void
357print_help (void)
358{
359 char *myport; 332 char *myport;
360 xasprintf (&myport, "%d", SSH_DFL_PORT); 333 xasprintf(&myport, "%d", SSH_DFL_PORT);
361 334
362 print_revision (progname, NP_VERSION); 335 print_revision(progname, NP_VERSION);
363 336
364 printf ("Copyright (c) 1999 Remi Paulmier <remi@sinfomic.fr>\n"); 337 printf("Copyright (c) 1999 Remi Paulmier <remi@sinfomic.fr>\n");
365 printf (COPYRIGHT, copyright, email); 338 printf(COPYRIGHT, copyright, email);
366 339
367 printf ("%s\n", _("Try to connect to an SSH server at specified server and port")); 340 printf("%s\n", _("Try to connect to an SSH server at specified server and port"));
368 341
369 printf ("\n\n"); 342 printf("\n\n");
370 343
371 print_usage (); 344 print_usage();
372 345
373 printf (UT_HELP_VRSN); 346 printf(UT_HELP_VRSN);
374 printf (UT_EXTRA_OPTS); 347 printf(UT_EXTRA_OPTS);
375 348
376 printf (UT_HOST_PORT, 'p', myport); 349 printf(UT_HOST_PORT, 'p', myport);
377 350
378 printf (UT_IPv46); 351 printf(UT_IPv46);
379 352
380 printf (UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); 353 printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT);
381 354
382 printf (" %s\n", "-r, --remote-version=STRING"); 355 printf(" %s\n", "-r, --remote-version=STRING");
383 printf (" %s\n", _("Alert if string doesn't match expected server version (ex: OpenSSH_3.9p1)")); 356 printf(" %s\n", _("Alert if string doesn't match expected server version (ex: OpenSSH_3.9p1)"));
384 357
385 printf (" %s\n", "-P, --remote-protocol=STRING"); 358 printf(" %s\n", "-P, --remote-protocol=STRING");
386 printf (" %s\n", _("Alert if protocol doesn't match expected protocol version (ex: 2.0)")); 359 printf(" %s\n", _("Alert if protocol doesn't match expected protocol version (ex: 2.0)"));
387 360
388 printf (UT_VERBOSE); 361 printf(UT_VERBOSE);
389 362
390 printf (UT_SUPPORT); 363 printf(UT_SUPPORT);
391} 364}
392 365
393 366void print_usage(void) {
394 367 printf("%s\n", _("Usage:"));
395void 368 printf("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] <host>\n", progname);
396print_usage (void)
397{
398 printf ("%s\n", _("Usage:"));
399 printf ("%s [-4|-6] [-t <timeout>] [-r <remote version>] [-p <port>] <host>\n", progname);
400} 369}
401