summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorHolger Weiss <hweiss@users.sourceforge.net>2007-09-15 14:25:56 (GMT)
committerHolger Weiss <hweiss@users.sourceforge.net>2007-09-15 14:25:56 (GMT)
commit05a980ba4bd3de0540771000955bd3235ad17acd (patch)
tree7bb3189713eb055678648274e1aea0d6bfc371ef
parentc11f63ff7eeb72ea220faec778e1b8bd6651b9f7 (diff)
downloadmonitoring-plugins-05a980ba4bd3de0540771000955bd3235ad17acd.tar.gz
Properly handle SMTP server responses which are split into multiple
packets (noted by Chris Adams on nagiosplug-help@). TODO: The new recvline()/recvlines() functions should buffer received data instead of reading one byte at a time and they should be moved to netutils.c so that other plugins can use them, too. git-svn-id: https://nagiosplug.svn.sourceforge.net/svnroot/nagiosplug/nagiosplug/trunk@1780 f882894a-f735-0410-b71e-b25c423dba1c
-rw-r--r--NEWS1
-rw-r--r--plugins/check_smtp.c90
2 files changed, 73 insertions, 18 deletions
diff --git a/NEWS b/NEWS
index b687f6f..d9ec3f6 100644
--- a/NEWS
+++ b/NEWS
@@ -15,6 +15,7 @@ This file documents the major additions and syntax changes between releases.
15 address to use in the DHCP request 15 address to use in the DHCP request
16 The check_dhcp -r and -s options now accept host names, too 16 The check_dhcp -r and -s options now accept host names, too
17 Fix possible check_icmp bus errors on some (non-x86/AMD64) platforms 17 Fix possible check_icmp bus errors on some (non-x86/AMD64) platforms
18 Fix check_smtp's handling of multiple-packet server responses
18 19
191.4.9 4th June 2006 201.4.9 4th June 2006
20 Inclusion of contrib/check_cluster2 as check_cluster with some improvements 21 Inclusion of contrib/check_cluster2 as check_cluster with some improvements
diff --git a/plugins/check_smtp.c b/plugins/check_smtp.c
index 8d392cc..79c7cd3 100644
--- a/plugins/check_smtp.c
+++ b/plugins/check_smtp.c
@@ -40,6 +40,8 @@ const char *revision = "$Revision$";
40const char *copyright = "2000-2006"; 40const char *copyright = "2000-2006";
41const char *email = "nagiosplug-devel@lists.sourceforge.net"; 41const char *email = "nagiosplug-devel@lists.sourceforge.net";
42 42
43#include <ctype.h>
44
43#include "common.h" 45#include "common.h"
44#include "netutils.h" 46#include "netutils.h"
45#include "utils.h" 47#include "utils.h"
@@ -75,6 +77,8 @@ int validate_arguments (void);
75void print_help (void); 77void print_help (void);
76void print_usage (void); 78void print_usage (void);
77void smtp_quit(void); 79void smtp_quit(void);
80int recvline(char *, size_t);
81int recvlines(char *, size_t);
78int my_close(void); 82int my_close(void);
79 83
80#include "regex.h" 84#include "regex.h"
@@ -116,7 +120,6 @@ char buffer[MAX_INPUT_BUFFER];
116enum { 120enum {
117 TCP_PROTOCOL = 1, 121 TCP_PROTOCOL = 1,
118 UDP_PROTOCOL = 2, 122 UDP_PROTOCOL = 2,
119 MAXBUF = 1024
120}; 123};
121 124
122/* written by lauri alanko */ 125/* written by lauri alanko */
@@ -222,7 +225,7 @@ main (int argc, char **argv)
222 225
223 /* watch for the SMTP connection string and */ 226 /* watch for the SMTP connection string and */
224 /* return a WARNING status if we couldn't read any data */ 227 /* return a WARNING status if we couldn't read any data */
225 if (recv (sd, buffer, MAX_INPUT_BUFFER - 1, 0) == -1) { 228 if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) {
226 printf (_("recv() failed\n")); 229 printf (_("recv() failed\n"));
227 result = STATE_WARNING; 230 result = STATE_WARNING;
228 } 231 }
@@ -246,11 +249,10 @@ main (int argc, char **argv)
246 send(sd, helocmd, strlen(helocmd), 0); 249 send(sd, helocmd, strlen(helocmd), 0);
247 250
248 /* allow for response to helo command to reach us */ 251 /* allow for response to helo command to reach us */
249 if(read (sd, buffer, MAXBUF - 1) < 0){ 252 if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) {
250 printf (_("recv() failed\n")); 253 printf (_("recv() failed\n"));
251 return STATE_WARNING; 254 return STATE_WARNING;
252 } else if(use_ehlo){ 255 } else if(use_ehlo){
253 buffer[MAXBUF-1]='\0';
254 if(strstr(buffer, "250 STARTTLS") != NULL || 256 if(strstr(buffer, "250 STARTTLS") != NULL ||
255 strstr(buffer, "250-STARTTLS") != NULL){ 257 strstr(buffer, "250-STARTTLS") != NULL){
256 supports_tls=TRUE; 258 supports_tls=TRUE;
@@ -268,7 +270,7 @@ main (int argc, char **argv)
268 /* send the STARTTLS command */ 270 /* send the STARTTLS command */
269 send(sd, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0); 271 send(sd, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0);
270 272
271 recv(sd,buffer, MAX_INPUT_BUFFER-1, 0); /* wait for it */ 273 recvlines(buffer, MAX_INPUT_BUFFER); /* wait for it */
272 if (!strstr (buffer, server_expect)) { 274 if (!strstr (buffer, server_expect)) {
273 printf (_("Server does not support STARTTLS\n")); 275 printf (_("Server does not support STARTTLS\n"));
274 smtp_quit(); 276 smtp_quit();
@@ -302,13 +304,12 @@ main (int argc, char **argv)
302 } 304 }
303 if (verbose) 305 if (verbose)
304 printf(_("sent %s"), helocmd); 306 printf(_("sent %s"), helocmd);
305 if ((n = my_recv(buffer, MAX_INPUT_BUFFER - 1)) <= 0) { 307 if ((n = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) {
306 printf("%s\n", _("SMTP UNKNOWN - Cannot read EHLO response via TLS.")); 308 printf("%s\n", _("SMTP UNKNOWN - Cannot read EHLO response via TLS."));
307 my_close(); 309 my_close();
308 return STATE_UNKNOWN; 310 return STATE_UNKNOWN;
309 } 311 }
310 if (verbose) { 312 if (verbose) {
311 buffer[n] = '\0';
312 printf("%s", buffer); 313 printf("%s", buffer);
313 } 314 }
314 315
@@ -337,16 +338,14 @@ main (int argc, char **argv)
337 */ 338 */
338 if (smtp_use_dummycmd) { 339 if (smtp_use_dummycmd) {
339 my_send(cmd_str, strlen(cmd_str)); 340 my_send(cmd_str, strlen(cmd_str));
340 my_recv(buffer, MAX_INPUT_BUFFER-1); 341 if (recvlines(buffer, MAX_INPUT_BUFFER) >= 1 && verbose)
341 if (verbose)
342 printf("%s", buffer); 342 printf("%s", buffer);
343 } 343 }
344 344
345 while (n < ncommands) { 345 while (n < ncommands) {
346 asprintf (&cmd_str, "%s%s", commands[n], "\r\n"); 346 asprintf (&cmd_str, "%s%s", commands[n], "\r\n");
347 my_send(cmd_str, strlen(cmd_str)); 347 my_send(cmd_str, strlen(cmd_str));
348 my_recv(buffer, MAX_INPUT_BUFFER-1); 348 if (recvlines(buffer, MAX_INPUT_BUFFER) >= 1 && verbose)
349 if (verbose)
350 printf("%s", buffer); 349 printf("%s", buffer);
351 strip (buffer); 350 strip (buffer);
352 if (n < nresponses) { 351 if (n < nresponses) {
@@ -395,12 +394,11 @@ main (int argc, char **argv)
395 if (verbose) 394 if (verbose)
396 printf (_("sent %s\n"), "AUTH LOGIN"); 395 printf (_("sent %s\n"), "AUTH LOGIN");
397 396
398 if((ret = my_recv(buffer, MAXBUF - 1)) < 0){ 397 if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) {
399 asprintf(&error_msg, _("recv() failed after AUTH LOGIN, ")); 398 asprintf(&error_msg, _("recv() failed after AUTH LOGIN, "));
400 result = STATE_WARNING; 399 result = STATE_WARNING;
401 break; 400 break;
402 } 401 }
403 buffer[ret] = 0;
404 if (verbose) 402 if (verbose)
405 printf (_("received %s\n"), buffer); 403 printf (_("received %s\n"), buffer);
406 404
@@ -417,12 +415,11 @@ main (int argc, char **argv)
417 if (verbose) 415 if (verbose)
418 printf (_("sent %s\n"), abuf); 416 printf (_("sent %s\n"), abuf);
419 417
420 if ((ret = my_recv(buffer, MAX_INPUT_BUFFER-1)) == -1) { 418 if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) {
421 result = STATE_CRITICAL; 419 result = STATE_CRITICAL;
422 asprintf(&error_msg, _("recv() failed after sending authuser, ")); 420 asprintf(&error_msg, _("recv() failed after sending authuser, "));
423 break; 421 break;
424 } 422 }
425 buffer[ret] = 0;
426 if (verbose) { 423 if (verbose) {
427 printf (_("received %s\n"), buffer); 424 printf (_("received %s\n"), buffer);
428 } 425 }
@@ -438,12 +435,11 @@ main (int argc, char **argv)
438 if (verbose) { 435 if (verbose) {
439 printf (_("sent %s\n"), abuf); 436 printf (_("sent %s\n"), abuf);
440 } 437 }
441 if ((ret = my_recv(buffer, MAX_INPUT_BUFFER-1)) == -1) { 438 if ((ret = recvlines(buffer, MAX_INPUT_BUFFER)) <= 0) {
442 result = STATE_CRITICAL; 439 result = STATE_CRITICAL;
443 asprintf(&error_msg, _("recv() failed after sending authpass, ")); 440 asprintf(&error_msg, _("recv() failed after sending authpass, "));
444 break; 441 break;
445 } 442 }
446 buffer[ret] = 0;
447 if (verbose) { 443 if (verbose) {
448 printf (_("received %s\n"), buffer); 444 printf (_("received %s\n"), buffer);
449 } 445 }
@@ -715,7 +711,7 @@ smtp_quit(void)
715 printf(_("sent %s\n"), "QUIT"); 711 printf(_("sent %s\n"), "QUIT");
716 712
717 /* read the response but don't care about problems */ 713 /* read the response but don't care about problems */
718 bytes = my_recv(buffer, MAXBUF - 1); 714 bytes = recvlines(buffer, MAX_INPUT_BUFFER);
719 if (verbose) { 715 if (verbose) {
720 if (bytes < 0) 716 if (bytes < 0)
721 printf(_("recv() failed after QUIT.")); 717 printf(_("recv() failed after QUIT."));
@@ -729,6 +725,64 @@ smtp_quit(void)
729} 725}
730 726
731 727
728/*
729 * Receive one line, copy it into buf and nul-terminate it. Returns the
730 * number of bytes written to buf (excluding the '\0') or 0 on EOF or <0 on
731 * error.
732 *
733 * TODO: Reading one byte at a time is very inefficient. Replace this by a
734 * function which buffers the data, move that to netutils.c and change
735 * check_smtp and other plugins to use that. Also, remove (\r)\n.
736 */
737int
738recvline(char *buf, size_t bufsize)
739{
740 int result;
741 unsigned i;
742
743 for (i = result = 0; i < bufsize - 1; i++) {
744 if ((result = my_recv(&buf[i], 1)) != 1)
745 break;
746 if (buf[i] == '\n') {
747 buf[++i] = '\0';
748 return i;
749 }
750 }
751 return (result == 1 || i == 0) ? -2 : result; /* -2 if out of space */
752}
753
754
755/*
756 * Receive one or more lines, copy them into buf and nul-terminate it. Returns
757 * the number of bytes written to buf (excluding the '\0') or 0 on EOF or <0 on
758 * error. Works for all protocols which format multiline replies as follows:
759 *
760 * ``The format for multiline replies requires that every line, except the last,
761 * begin with the reply code, followed immediately by a hyphen, `-' (also known
762 * as minus), followed by text. The last line will begin with the reply code,
763 * followed immediately by <SP>, optionally some text, and <CRLF>. As noted
764 * above, servers SHOULD send the <SP> if subsequent text is not sent, but
765 * clients MUST be prepared for it to be omitted.'' (RFC 2821, 4.2.1)
766 *
767 * TODO: Move this to netutils.c. Also, remove \r and possibly the final \n.
768 */
769int
770recvlines(char *buf, size_t bufsize)
771{
772 int result, i;
773
774 for (i = 0; /* forever */; i += result)
775 if (!((result = recvline(buf + i, bufsize - i)) > 3 &&
776 isdigit((int)buf[i]) &&
777 isdigit((int)buf[i + 1]) &&
778 isdigit((int)buf[i + 2]) &&
779 buf[i + 3] == '-'))
780 break;
781
782 return (result <= 0) ? result : result + i;
783}
784
785
732int 786int
733my_close (void) 787my_close (void)
734{ 788{