[Nagiosplug-checkins] nagiosplug/plugins check_smtp.c,1.46,1.47

M. Sean Finney seanius at users.sourceforge.net
Thu Oct 13 03:14:20 CEST 2005


Update of /cvsroot/nagiosplug/nagiosplug/plugins
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv7122/plugins

Modified Files:
	check_smtp.c 
Log Message:
multiple fixes in check_smtp from debian (bts #285554):
- fix for double free via SSL_CTX_free.  looks like the previous author
  knew this was a problem but didn't care enough to fix it ;p.
- use defines instead of const chars for SMTP strings.
- default to send our fqdn (via gethostbyname lookup on gethostname)
  in the HELO string, as this is an RFC/SMTP requirement.  overridable
  via cmdline.
- use EHLO instead of HELO if using STARTTLS, as it is not SMTP but
  ESMTP.
- verify the server supports STARTTLS before initializing it.
- always send QUIT before disconnecting when possible.


Index: check_smtp.c
===================================================================
RCS file: /cvsroot/nagiosplug/nagiosplug/plugins/check_smtp.c,v
retrieving revision 1.46
retrieving revision 1.47
diff -u -d -r1.46 -r1.47
--- check_smtp.c	7 Apr 2005 04:33:33 -0000	1.46
+++ check_smtp.c	13 Oct 2005 10:11:25 -0000	1.47
@@ -59,10 +59,17 @@
 enum {
 	SMTP_PORT	= 25
 };
-const char *SMTP_EXPECT = "220";
-const char *SMTP_HELO = "HELO ";
-const char *SMTP_QUIT	= "QUIT\r\n";
-const char *SMTP_STARTTLS = "STARTTLS\r\n";
+#define SMTP_EXPECT "220"
+#define SMTP_HELO "HELO "
+#define SMTP_EHLO "EHLO "
+#define SMTP_QUIT "QUIT\r\n"
+#define SMTP_STARTTLS "STARTTLS\r\n"
+
+#ifndef HOST_MAX_BYTES
+#define HOST_MAX_BYTES 255
+#endif
+
+#define EHLO_SUPPORTS_STARTTLS 1
 
 int process_arguments (int, char **);
 int validate_arguments (void);
@@ -101,6 +108,9 @@
 int check_critical_time = FALSE;
 int verbose = 0;
 int use_ssl = FALSE;
+short use_ehlo = FALSE;
+short ssl_established = TRUE;
+char *localhostname = NULL;
 int sd;
 char buffer[MAX_INPUT_BUFFER];
 enum {
@@ -112,7 +122,7 @@
 int
 main (int argc, char **argv)
 {
-
+	short supports_tls=FALSE;
 	int n = 0;
 	double elapsed_time;
 	long microsec;
@@ -120,6 +130,7 @@
 	char *cmd_str = NULL;
 	char *helocmd = NULL;
 	struct timeval tv;
+	struct hostent *hp;
 
 	setlocale (LC_ALL, "");
 	bindtextdomain (PACKAGE, LOCALEDIR);
@@ -129,12 +140,26 @@
 		usage4 (_("Could not parse arguments"));
 
 	/* initialize the HELO command with the localhostname */
-#ifndef HOST_MAX_BYTES
-#define HOST_MAX_BYTES 255
-#endif
-	helocmd = malloc (HOST_MAX_BYTES);
-	gethostname(helocmd, HOST_MAX_BYTES);
-	asprintf (&helocmd, "%s%s%s", SMTP_HELO, helocmd, "\r\n");
+	if(! localhostname){
+		localhostname = malloc (HOST_MAX_BYTES);
+		if(!localhostname){
+			printf(_("malloc() failed!\n"));
+			return STATE_CRITICAL;
+		}
+		if(gethostname(localhostname, HOST_MAX_BYTES)){
+			printf(_("gethostname() failed!\n"));
+			return STATE_CRITICAL;
+		}
+		hp = gethostbyname(localhostname);
+		if(!hp) helocmd = localhostname;
+		else helocmd = hp->h_name;
+	} else {
+		helocmd = localhostname;
+	}
+	if(use_ehlo)
+		asprintf (&helocmd, "%s%s%s", SMTP_EHLO, helocmd, "\r\n");
+	else
+		asprintf (&helocmd, "%s%s%s", SMTP_HELO, helocmd, "\r\n");
 
 	/* initialize the MAIL command with optional FROM command  */
 	asprintf (&cmd_str, "%sFROM: %s%s", mail_command, from_arg, "\r\n");
@@ -178,11 +203,26 @@
 			}
 		}
 
-		/* send the HELO command */
+		/* send the HELO/EHLO command */
 		send(sd, helocmd, strlen(helocmd), 0);
 
 		/* allow for response to helo command to reach us */
-		read (sd, buffer, MAXBUF - 1);
+		if(read (sd, buffer, MAXBUF - 1) < 0){
+			printf (_("recv() failed\n"));
+			return STATE_WARNING;
+		} else if(use_ehlo){
+			buffer[MAXBUF-1]='\0';
+			if(strstr(buffer, "250 STARTTLS") != NULL ||
+			   strstr(buffer, "250-STARTTLS") != NULL){
+				supports_tls=TRUE;
+			}
+		}
+
+		if(use_ssl && ! supports_tls){
+			printf(_("WARNING - TLS not supported by server\n"));
+			send (sd, SMTP_QUIT, strlen (SMTP_QUIT), 0);
+			return STATE_WARNING;
+		}
 
 #ifdef HAVE_SSL
 		if(use_ssl) {
@@ -192,11 +232,14 @@
 		  recv(sd,buffer, MAX_INPUT_BUFFER-1, 0); /* wait for it */
 		  if (!strstr (buffer, server_expect)) {
 		    printf (_("Server does not support STARTTLS\n"));
+		    send (sd, SMTP_QUIT, strlen (SMTP_QUIT), 0);
 		    return STATE_UNKNOWN;
 		  }
 		  if(connect_STARTTLS() != OK) {
 		    printf (_("CRITICAL - Cannot create SSL context.\n"));
 		    return STATE_CRITICAL;
+		  } else {
+			ssl_established = TRUE;
 		  }
 		  if ( check_cert ) {
 		    if ((server_cert = SSL_get_peer_certificate (ssl)) != NULL) {
@@ -333,6 +376,7 @@
 		{"timeout", required_argument, 0, 't'},
 		{"port", required_argument, 0, 'p'},
 		{"from", required_argument, 0, 'f'},
+		{"fqdn", required_argument, 0, 'F'},
 		{"command", required_argument, 0, 'C'},
 		{"response", required_argument, 0, 'R'},
 		{"nocommand", required_argument, 0, 'n'},
@@ -359,7 +403,7 @@
 	}
 
 	while (1) {
-		c = getopt_long (argc, argv, "+hVv46t:p:f:e:c:w:H:C:R:SD:",
+		c = getopt_long (argc, argv, "+hVv46t:p:f:e:c:w:H:C:R:SD:F:",
 		                 longopts, &option);
 
 		if (c == -1 || c == EOF)
@@ -380,6 +424,10 @@
 			else
 				usage4 (_("Port must be a positive integer"));
 			break;
+		case 'F':
+		/* localhostname */
+			localhostname = strdup(optarg);
+			break;
 		case 'f':									/* from argument */
 			from_arg = optarg;
 			smtp_use_dummycmd = 1;
@@ -439,6 +487,7 @@
 		case 'S':
 		/* starttls */
 			use_ssl = TRUE;
+			use_ehlo = TRUE;
 			break;
 		case 'D':
 		/* Check SSL cert validity */
@@ -581,7 +630,7 @@
 
   /* Initialize SSL context */
   SSLeay_add_ssl_algorithms ();
-  meth = SSLv2_client_method ();
+  meth = SSLv23_client_method ();
   SSL_load_error_strings ();
   if ((ctx = SSL_CTX_new (meth)) == NULL)
     {
@@ -602,11 +651,6 @@
     {
       printf (_("CRITICAL - Cannot initiate SSL handshake.\n"));
     }
-  /* this causes a seg faul
-     not sure why, being sloppy
-     and commenting it out */
-  /*  SSL_free (ssl); */
-  SSL_CTX_free(ctx);
   my_close();
   
   return STATE_CRITICAL;
@@ -708,7 +752,7 @@
 my_close (void)
 {
 #ifdef HAVE_SSL
-  if (use_ssl == TRUE) {
+  if (use_ssl == TRUE && ssl_established == TRUE) {
     SSL_shutdown (ssl);
     SSL_free (ssl);
     SSL_CTX_free (ctx);





More information about the Commits mailing list