summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/check_smtp.c86
1 files changed, 65 insertions, 21 deletions
diff --git a/plugins/check_smtp.c b/plugins/check_smtp.c
index f0bc7363..3bb6a32b 100644
--- a/plugins/check_smtp.c
+++ b/plugins/check_smtp.c
@@ -59,10 +59,17 @@ int check_certificate (X509 **);
59enum { 59enum {
60 SMTP_PORT = 25 60 SMTP_PORT = 25
61}; 61};
62const char *SMTP_EXPECT = "220"; 62#define SMTP_EXPECT "220"
63const char *SMTP_HELO = "HELO "; 63#define SMTP_HELO "HELO "
64const char *SMTP_QUIT = "QUIT\r\n"; 64#define SMTP_EHLO "EHLO "
65const char *SMTP_STARTTLS = "STARTTLS\r\n"; 65#define SMTP_QUIT "QUIT\r\n"
66#define SMTP_STARTTLS "STARTTLS\r\n"
67
68#ifndef HOST_MAX_BYTES
69#define HOST_MAX_BYTES 255
70#endif
71
72#define EHLO_SUPPORTS_STARTTLS 1
66 73
67int process_arguments (int, char **); 74int process_arguments (int, char **);
68int validate_arguments (void); 75int validate_arguments (void);
@@ -101,6 +108,9 @@ int critical_time = 0;
101int check_critical_time = FALSE; 108int check_critical_time = FALSE;
102int verbose = 0; 109int verbose = 0;
103int use_ssl = FALSE; 110int use_ssl = FALSE;
111short use_ehlo = FALSE;
112short ssl_established = TRUE;
113char *localhostname = NULL;
104int sd; 114int sd;
105char buffer[MAX_INPUT_BUFFER]; 115char buffer[MAX_INPUT_BUFFER];
106enum { 116enum {
@@ -112,7 +122,7 @@ enum {
112int 122int
113main (int argc, char **argv) 123main (int argc, char **argv)
114{ 124{
115 125 short supports_tls=FALSE;
116 int n = 0; 126 int n = 0;
117 double elapsed_time; 127 double elapsed_time;
118 long microsec; 128 long microsec;
@@ -120,6 +130,7 @@ main (int argc, char **argv)
120 char *cmd_str = NULL; 130 char *cmd_str = NULL;
121 char *helocmd = NULL; 131 char *helocmd = NULL;
122 struct timeval tv; 132 struct timeval tv;
133 struct hostent *hp;
123 134
124 setlocale (LC_ALL, ""); 135 setlocale (LC_ALL, "");
125 bindtextdomain (PACKAGE, LOCALEDIR); 136 bindtextdomain (PACKAGE, LOCALEDIR);
@@ -129,12 +140,26 @@ main (int argc, char **argv)
129 usage4 (_("Could not parse arguments")); 140 usage4 (_("Could not parse arguments"));
130 141
131 /* initialize the HELO command with the localhostname */ 142 /* initialize the HELO command with the localhostname */
132#ifndef HOST_MAX_BYTES 143 if(! localhostname){
133#define HOST_MAX_BYTES 255 144 localhostname = malloc (HOST_MAX_BYTES);
134#endif 145 if(!localhostname){
135 helocmd = malloc (HOST_MAX_BYTES); 146 printf(_("malloc() failed!\n"));
136 gethostname(helocmd, HOST_MAX_BYTES); 147 return STATE_CRITICAL;
137 asprintf (&helocmd, "%s%s%s", SMTP_HELO, helocmd, "\r\n"); 148 }
149 if(gethostname(localhostname, HOST_MAX_BYTES)){
150 printf(_("gethostname() failed!\n"));
151 return STATE_CRITICAL;
152 }
153 hp = gethostbyname(localhostname);
154 if(!hp) helocmd = localhostname;
155 else helocmd = hp->h_name;
156 } else {
157 helocmd = localhostname;
158 }
159 if(use_ehlo)
160 asprintf (&helocmd, "%s%s%s", SMTP_EHLO, helocmd, "\r\n");
161 else
162 asprintf (&helocmd, "%s%s%s", SMTP_HELO, helocmd, "\r\n");
138 163
139 /* initialize the MAIL command with optional FROM command */ 164 /* initialize the MAIL command with optional FROM command */
140 asprintf (&cmd_str, "%sFROM: %s%s", mail_command, from_arg, "\r\n"); 165 asprintf (&cmd_str, "%sFROM: %s%s", mail_command, from_arg, "\r\n");
@@ -178,11 +203,26 @@ main (int argc, char **argv)
178 } 203 }
179 } 204 }
180 205
181 /* send the HELO command */ 206 /* send the HELO/EHLO command */
182 send(sd, helocmd, strlen(helocmd), 0); 207 send(sd, helocmd, strlen(helocmd), 0);
183 208
184 /* allow for response to helo command to reach us */ 209 /* allow for response to helo command to reach us */
185 read (sd, buffer, MAXBUF - 1); 210 if(read (sd, buffer, MAXBUF - 1) < 0){
211 printf (_("recv() failed\n"));
212 return STATE_WARNING;
213 } else if(use_ehlo){
214 buffer[MAXBUF-1]='\0';
215 if(strstr(buffer, "250 STARTTLS") != NULL ||
216 strstr(buffer, "250-STARTTLS") != NULL){
217 supports_tls=TRUE;
218 }
219 }
220
221 if(use_ssl && ! supports_tls){
222 printf(_("WARNING - TLS not supported by server\n"));
223 send (sd, SMTP_QUIT, strlen (SMTP_QUIT), 0);
224 return STATE_WARNING;
225 }
186 226
187#ifdef HAVE_SSL 227#ifdef HAVE_SSL
188 if(use_ssl) { 228 if(use_ssl) {
@@ -192,11 +232,14 @@ main (int argc, char **argv)
192 recv(sd,buffer, MAX_INPUT_BUFFER-1, 0); /* wait for it */ 232 recv(sd,buffer, MAX_INPUT_BUFFER-1, 0); /* wait for it */
193 if (!strstr (buffer, server_expect)) { 233 if (!strstr (buffer, server_expect)) {
194 printf (_("Server does not support STARTTLS\n")); 234 printf (_("Server does not support STARTTLS\n"));
235 send (sd, SMTP_QUIT, strlen (SMTP_QUIT), 0);
195 return STATE_UNKNOWN; 236 return STATE_UNKNOWN;
196 } 237 }
197 if(connect_STARTTLS() != OK) { 238 if(connect_STARTTLS() != OK) {
198 printf (_("CRITICAL - Cannot create SSL context.\n")); 239 printf (_("CRITICAL - Cannot create SSL context.\n"));
199 return STATE_CRITICAL; 240 return STATE_CRITICAL;
241 } else {
242 ssl_established = TRUE;
200 } 243 }
201 if ( check_cert ) { 244 if ( check_cert ) {
202 if ((server_cert = SSL_get_peer_certificate (ssl)) != NULL) { 245 if ((server_cert = SSL_get_peer_certificate (ssl)) != NULL) {
@@ -333,6 +376,7 @@ process_arguments (int argc, char **argv)
333 {"timeout", required_argument, 0, 't'}, 376 {"timeout", required_argument, 0, 't'},
334 {"port", required_argument, 0, 'p'}, 377 {"port", required_argument, 0, 'p'},
335 {"from", required_argument, 0, 'f'}, 378 {"from", required_argument, 0, 'f'},
379 {"fqdn", required_argument, 0, 'F'},
336 {"command", required_argument, 0, 'C'}, 380 {"command", required_argument, 0, 'C'},
337 {"response", required_argument, 0, 'R'}, 381 {"response", required_argument, 0, 'R'},
338 {"nocommand", required_argument, 0, 'n'}, 382 {"nocommand", required_argument, 0, 'n'},
@@ -359,7 +403,7 @@ process_arguments (int argc, char **argv)
359 } 403 }
360 404
361 while (1) { 405 while (1) {
362 c = getopt_long (argc, argv, "+hVv46t:p:f:e:c:w:H:C:R:SD:", 406 c = getopt_long (argc, argv, "+hVv46t:p:f:e:c:w:H:C:R:SD:F:",
363 longopts, &option); 407 longopts, &option);
364 408
365 if (c == -1 || c == EOF) 409 if (c == -1 || c == EOF)
@@ -380,6 +424,10 @@ process_arguments (int argc, char **argv)
380 else 424 else
381 usage4 (_("Port must be a positive integer")); 425 usage4 (_("Port must be a positive integer"));
382 break; 426 break;
427 case 'F':
428 /* localhostname */
429 localhostname = strdup(optarg);
430 break;
383 case 'f': /* from argument */ 431 case 'f': /* from argument */
384 from_arg = optarg; 432 from_arg = optarg;
385 smtp_use_dummycmd = 1; 433 smtp_use_dummycmd = 1;
@@ -439,6 +487,7 @@ process_arguments (int argc, char **argv)
439 case 'S': 487 case 'S':
440 /* starttls */ 488 /* starttls */
441 use_ssl = TRUE; 489 use_ssl = TRUE;
490 use_ehlo = TRUE;
442 break; 491 break;
443 case 'D': 492 case 'D':
444 /* Check SSL cert validity */ 493 /* Check SSL cert validity */
@@ -581,7 +630,7 @@ connect_STARTTLS (void)
581 630
582 /* Initialize SSL context */ 631 /* Initialize SSL context */
583 SSLeay_add_ssl_algorithms (); 632 SSLeay_add_ssl_algorithms ();
584 meth = SSLv2_client_method (); 633 meth = SSLv23_client_method ();
585 SSL_load_error_strings (); 634 SSL_load_error_strings ();
586 if ((ctx = SSL_CTX_new (meth)) == NULL) 635 if ((ctx = SSL_CTX_new (meth)) == NULL)
587 { 636 {
@@ -602,11 +651,6 @@ connect_STARTTLS (void)
602 { 651 {
603 printf (_("CRITICAL - Cannot initiate SSL handshake.\n")); 652 printf (_("CRITICAL - Cannot initiate SSL handshake.\n"));
604 } 653 }
605 /* this causes a seg faul
606 not sure why, being sloppy
607 and commenting it out */
608 /* SSL_free (ssl); */
609 SSL_CTX_free(ctx);
610 my_close(); 654 my_close();
611 655
612 return STATE_CRITICAL; 656 return STATE_CRITICAL;
@@ -708,7 +752,7 @@ int
708my_close (void) 752my_close (void)
709{ 753{
710#ifdef HAVE_SSL 754#ifdef HAVE_SSL
711 if (use_ssl == TRUE) { 755 if (use_ssl == TRUE && ssl_established == TRUE) {
712 SSL_shutdown (ssl); 756 SSL_shutdown (ssl);
713 SSL_free (ssl); 757 SSL_free (ssl);
714 SSL_CTX_free (ctx); 758 SSL_CTX_free (ctx);