diff options
Diffstat (limited to 'plugins')
| -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 f0bc7363..3bb6a32b 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); |
