summaryrefslogtreecommitdiffstats
path: root/plugins/check_ssh.c
diff options
context:
space:
mode:
authorAnton Lofgren <alofgren@op5.com>2013-10-21 06:18:30 (GMT)
committerLorenz Kästle <lorenz.kaestle@netways.de>2022-01-14 14:34:08 (GMT)
commitcb0b3e245afcdc29e606299c93fc232ddd6d7cef (patch)
tree69f35f5d31087e4efcd830dd7b1d0b73b4467c2e /plugins/check_ssh.c
parent9899bc736f45400fa70bdee281f5f5b46490b805 (diff)
downloadmonitoring-plugins-cb0b3e245afcdc29e606299c93fc232ddd6d7cef.tar.gz
check_ssh: properly parse a delayed version control string
This resolves an issue with SSH servers which do not respond with their version control string as the first thing in the SSH protocol version exchange phase after connection establishment. This patch also makes sure that we disregard a potential comment in the version exchange string to avoid nonsense mismatches. In the future, we might want to add the capability to match against a user specified comment. In addition, the patch largely improves the communication towards the server, which adds better protocol adherence. Of course, new test cases are added to support the trigger and guard against regressions of the bugs solved by this patch. This fixes op5#7945 (https://bugs.op5.com/view.php?id=7945) Signed-off-by: Anton Lofgren <alofgren@op5.com>
Diffstat (limited to 'plugins/check_ssh.c')
-rw-r--r--plugins/check_ssh.c122
1 files changed, 85 insertions, 37 deletions
diff --git a/plugins/check_ssh.c b/plugins/check_ssh.c
index 8ccbd5a..8a3abb0 100644
--- a/plugins/check_ssh.c
+++ b/plugins/check_ssh.c
@@ -215,8 +215,13 @@ ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol
215{ 215{
216 int sd; 216 int sd;
217 int result; 217 int result;
218 int len = 0;
219 ssize_t byte_offset = 0;
220 ssize_t recv_ret = 0;
221 char *version_control_string = NULL;
218 char *output = NULL; 222 char *output = NULL;
219 char *buffer = NULL; 223 char *buffer = NULL;
224 char *tmp= NULL, *saveptr = NULL;
220 char *ssh_proto = NULL; 225 char *ssh_proto = NULL;
221 char *ssh_server = NULL; 226 char *ssh_server = NULL;
222 static char *rev_no = VERSION; 227 static char *rev_no = VERSION;
@@ -231,51 +236,94 @@ ssh_connect (char *haddr, int hport, char *remote_version, char *remote_protocol
231 return result; 236 return result;
232 237
233 output = (char *) malloc (BUFF_SZ + 1); 238 output = (char *) malloc (BUFF_SZ + 1);
234 memset (output, 0, BUFF_SZ + 1); 239 memset(output, 0, BUFF_SZ+1);
235 recv (sd, output, BUFF_SZ, 0); 240 while (!version_control_string && (recv_ret = recv(sd, output+byte_offset, BUFF_SZ - byte_offset, 0)) > 0) {
236 if (strncmp (output, "SSH", 3)) { 241 if (strchr(output, '\n')) { /* we've got at least one full line, start parsing*/
237 printf (_("Server answer: %s"), output); 242 byte_offset = 0;
238 close(sd); 243 while (strchr(output+byte_offset, '\n') != NULL) {
244 /*Partition the buffer so that this line is a separate string,
245 * by replacing the newline with NUL*/
246 output[(strchr(output+byte_offset, '\n')-output)]= '\0';
247 len = strlen(output+byte_offset);
248 if (len >= 4) {
249 /*if the string starts with SSH-, this _should_ be a valid version control string*/
250 if (strncmp (output+byte_offset, "SSH-", 4) == 0) {
251 version_control_string = output+byte_offset;
252 break;
253 }
254 }
255
256 /*the start of the next line (if one exists) will be after the current one (+ NUL)*/
257 byte_offset+=len+1;
258 }
259 if(!version_control_string) {
260 /* move unconsumed data to beginning of buffer, null rest */
261 memmove((void *)output, (void *)output+byte_offset+1, BUFF_SZ - len+1);
262 memset(output+byte_offset+1, 0, BUFF_SZ-byte_offset+1);
263
264 /*start reading from end of current line chunk on next recv*/
265 byte_offset = strlen(output);
266 }
267 }
268 else {
269 byte_offset += recv_ret;
270 }
271 }
272 tmp = NULL;
273 if (recv_ret < 0) {
274 printf("SSH CRITICAL - %s", strerror(errno));
275 exit(STATE_CRITICAL);
276 }
277 if (!version_control_string) {
278 printf("SSH CRITICAL - No version control string received");
279 exit(STATE_CRITICAL);
280 }
281 strip (version_control_string);
282 if (verbose)
283 printf ("%s\n", version_control_string);
284 ssh_proto = version_control_string + 4;
285 ssh_server = ssh_proto + strspn (ssh_proto, "-0123456789.");
286
287 /* If there's a space in the version string, whatever's after the space is a comment
288 * (which is NOT part of the server name/version)*/
289 tmp = strchr(ssh_server, ' ');
290 if (tmp) {
291 ssh_server[tmp - ssh_server] = '\0';
292 }
293 if (strlen(ssh_proto) == 0 || strlen(ssh_server) == 0) {
294 printf(_("SSH CRITICAL - Invalid protocol version control string %s\n"), version_control_string);
239 exit (STATE_CRITICAL); 295 exit (STATE_CRITICAL);
240 } 296 }
241 else { 297 ssh_proto[strspn (ssh_proto, "0123456789. ")] = 0;
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;
248
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);
253
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);
260 }
261 298
262 if (remote_protocol && strcmp(remote_protocol, ssh_proto)) { 299 xasprintf (&buffer, "SSH-%s-check_ssh_%s\r\n", ssh_proto, rev_no);
263 printf 300 send (sd, buffer, strlen (buffer), MSG_DONTWAIT);
264 (_("SSH CRITICAL - %s (protocol %s) protocol version mismatch, expected '%s'\n"), 301 if (verbose)
265 ssh_server, ssh_proto, remote_protocol); 302 printf ("%s\n", buffer);
266 close(sd);
267 exit (STATE_CRITICAL);
268 }
269 303
270 elapsed_time = (double)deltime(tv) / 1.0e6; 304 if (remote_version && strcmp(remote_version, ssh_server)) {
305 printf
306 (_("SSH CRITICAL - %s (protocol %s) version mismatch, expected '%s'\n"),
307 ssh_server, ssh_proto, remote_version);
308 close(sd);
309 exit (STATE_CRITICAL);
310 }
271 311
312 if (remote_protocol && strcmp(remote_protocol, ssh_proto)) {
272 printf 313 printf
273 (_("SSH OK - %s (protocol %s) | %s\n"), 314 (_("SSH CRITICAL - %s (protocol %s) protocol version mismatch, expected '%s'\n"),
274 ssh_server, ssh_proto, fperfdata("time", elapsed_time, "s", 315 ssh_server, ssh_proto, remote_protocol);
275 FALSE, 0, FALSE, 0, TRUE, 0, TRUE, (int)socket_timeout));
276 close(sd); 316 close(sd);
277 exit (STATE_OK); 317 exit (STATE_CRITICAL);
278 } 318 }
319 elapsed_time = (double)deltime(tv) / 1.0e6;
320
321 printf
322 (_("SSH OK - %s (protocol %s) | %s\n"),
323 ssh_server, ssh_proto, fperfdata("time", elapsed_time, "s",
324 FALSE, 0, FALSE, 0, TRUE, 0, TRUE, (int)socket_timeout));
325 close(sd);
326 exit (STATE_OK);
279} 327}
280 328
281 329