diff options
-rw-r--r-- | plugins/check_smtp.c | 86 |
1 files changed, 65 insertions, 21 deletions
diff --git a/plugins/check_smtp.c b/plugins/check_smtp.c index f0bc736..3bb6a32 100644 --- a/plugins/check_smtp.c +++ b/plugins/check_smtp.c | |||
@@ -59,10 +59,17 @@ int check_certificate (X509 **); | |||
59 | enum { | 59 | enum { |
60 | SMTP_PORT = 25 | 60 | SMTP_PORT = 25 |
61 | }; | 61 | }; |
62 | const char *SMTP_EXPECT = "220"; | 62 | #define SMTP_EXPECT "220" |
63 | const char *SMTP_HELO = "HELO "; | 63 | #define SMTP_HELO "HELO " |
64 | const char *SMTP_QUIT = "QUIT\r\n"; | 64 | #define SMTP_EHLO "EHLO " |
65 | const 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 | ||
67 | int process_arguments (int, char **); | 74 | int process_arguments (int, char **); |
68 | int validate_arguments (void); | 75 | int validate_arguments (void); |
@@ -101,6 +108,9 @@ int critical_time = 0; | |||
101 | int check_critical_time = FALSE; | 108 | int check_critical_time = FALSE; |
102 | int verbose = 0; | 109 | int verbose = 0; |
103 | int use_ssl = FALSE; | 110 | int use_ssl = FALSE; |
111 | short use_ehlo = FALSE; | ||
112 | short ssl_established = TRUE; | ||
113 | char *localhostname = NULL; | ||
104 | int sd; | 114 | int sd; |
105 | char buffer[MAX_INPUT_BUFFER]; | 115 | char buffer[MAX_INPUT_BUFFER]; |
106 | enum { | 116 | enum { |
@@ -112,7 +122,7 @@ enum { | |||
112 | int | 122 | int |
113 | main (int argc, char **argv) | 123 | main (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 | |||
708 | my_close (void) | 752 | my_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); |