summaryrefslogtreecommitdiffstats
path: root/plugins/check_smtp.c
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/check_smtp.c')
-rw-r--r--plugins/check_smtp.c156
1 files changed, 118 insertions, 38 deletions
diff --git a/plugins/check_smtp.c b/plugins/check_smtp.c
index 1996c6d3..fc0ae2c4 100644
--- a/plugins/check_smtp.c
+++ b/plugins/check_smtp.c
@@ -3,7 +3,7 @@
3* Monitoring check_smtp plugin 3* Monitoring check_smtp plugin
4* 4*
5* License: GPL 5* License: GPL
6* Copyright (c) 2000-2007 Monitoring Plugins Development Team 6* Copyright (c) 2000-2023 Monitoring Plugins Development Team
7* 7*
8* Description: 8* Description:
9* 9*
@@ -42,27 +42,26 @@ const char *email = "devel@monitoring-plugins.org";
42#ifdef HAVE_SSL 42#ifdef HAVE_SSL
43int check_cert = FALSE; 43int check_cert = FALSE;
44int days_till_exp_warn, days_till_exp_crit; 44int days_till_exp_warn, days_till_exp_crit;
45# define my_recv(buf, len) ((use_ssl && ssl_established) ? np_net_ssl_read(buf, len) : read(sd, buf, len)) 45# define my_recv(buf, len) (((use_starttls || use_ssl) && ssl_established) ? np_net_ssl_read(buf, len) : read(sd, buf, len))
46# define my_send(buf, len) ((use_ssl && ssl_established) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0)) 46# define my_send(buf, len) (((use_starttls || use_ssl) && ssl_established) ? np_net_ssl_write(buf, len) : send(sd, buf, len, 0))
47#else /* ifndef HAVE_SSL */ 47#else /* ifndef HAVE_SSL */
48# define my_recv(buf, len) read(sd, buf, len) 48# define my_recv(buf, len) read(sd, buf, len)
49# define my_send(buf, len) send(sd, buf, len, 0) 49# define my_send(buf, len) send(sd, buf, len, 0)
50#endif 50#endif
51 51
52enum { 52enum {
53 SMTP_PORT = 25 53 SMTP_PORT = 25,
54 SMTPS_PORT = 465
54}; 55};
56#define PROXY_PREFIX "PROXY TCP4 0.0.0.0 0.0.0.0 25 25\r\n"
55#define SMTP_EXPECT "220" 57#define SMTP_EXPECT "220"
56#define SMTP_HELO "HELO " 58#define SMTP_HELO "HELO "
57#define SMTP_EHLO "EHLO " 59#define SMTP_EHLO "EHLO "
60#define SMTP_LHLO "LHLO "
58#define SMTP_QUIT "QUIT\r\n" 61#define SMTP_QUIT "QUIT\r\n"
59#define SMTP_STARTTLS "STARTTLS\r\n" 62#define SMTP_STARTTLS "STARTTLS\r\n"
60#define SMTP_AUTH_LOGIN "AUTH LOGIN\r\n" 63#define SMTP_AUTH_LOGIN "AUTH LOGIN\r\n"
61 64
62#ifndef HOST_MAX_BYTES
63#define HOST_MAX_BYTES 255
64#endif
65
66#define EHLO_SUPPORTS_STARTTLS 1 65#define EHLO_SUPPORTS_STARTTLS 1
67 66
68int process_arguments (int, char **); 67int process_arguments (int, char **);
@@ -85,6 +84,7 @@ int eflags = 0;
85int errcode, excode; 84int errcode, excode;
86 85
87int server_port = SMTP_PORT; 86int server_port = SMTP_PORT;
87int server_port_option = 0;
88char *server_address = NULL; 88char *server_address = NULL;
89char *server_expect = NULL; 89char *server_expect = NULL;
90char *mail_command = NULL; 90char *mail_command = NULL;
@@ -105,7 +105,11 @@ double critical_time = 0;
105int check_critical_time = FALSE; 105int check_critical_time = FALSE;
106int verbose = 0; 106int verbose = 0;
107int use_ssl = FALSE; 107int use_ssl = FALSE;
108int use_starttls = FALSE;
109int use_sni = FALSE;
110short use_proxy_prefix = FALSE;
108short use_ehlo = FALSE; 111short use_ehlo = FALSE;
112short use_lhlo = FALSE;
109short ssl_established = 0; 113short ssl_established = 0;
110char *localhostname = NULL; 114char *localhostname = NULL;
111int sd; 115int sd;
@@ -128,6 +132,7 @@ main (int argc, char **argv)
128 char *cmd_str = NULL; 132 char *cmd_str = NULL;
129 char *helocmd = NULL; 133 char *helocmd = NULL;
130 char *error_msg = ""; 134 char *error_msg = "";
135 char *server_response = NULL;
131 struct timeval tv; 136 struct timeval tv;
132 137
133 /* Catch pipe errors in read/write - sometimes occurs when writing QUIT */ 138 /* Catch pipe errors in read/write - sometimes occurs when writing QUIT */
@@ -155,7 +160,9 @@ main (int argc, char **argv)
155 return STATE_CRITICAL; 160 return STATE_CRITICAL;
156 } 161 }
157 } 162 }
158 if(use_ehlo) 163 if(use_lhlo)
164 xasprintf (&helocmd, "%s%s%s", SMTP_LHLO, localhostname, "\r\n");
165 else if(use_ehlo)
159 xasprintf (&helocmd, "%s%s%s", SMTP_EHLO, localhostname, "\r\n"); 166 xasprintf (&helocmd, "%s%s%s", SMTP_EHLO, localhostname, "\r\n");
160 else 167 else
161 xasprintf (&helocmd, "%s%s%s", SMTP_HELO, localhostname, "\r\n"); 168 xasprintf (&helocmd, "%s%s%s", SMTP_HELO, localhostname, "\r\n");
@@ -182,6 +189,26 @@ main (int argc, char **argv)
182 result = my_tcp_connect (server_address, server_port, &sd); 189 result = my_tcp_connect (server_address, server_port, &sd);
183 190
184 if (result == STATE_OK) { /* we connected */ 191 if (result == STATE_OK) { /* we connected */
192 /* If requested, send PROXY header */
193 if (use_proxy_prefix) {
194 if (verbose)
195 printf ("Sending header %s\n", PROXY_PREFIX);
196 my_send(PROXY_PREFIX, strlen(PROXY_PREFIX));
197 }
198
199#ifdef HAVE_SSL
200 if (use_ssl) {
201 result = np_net_ssl_init_with_hostname(sd, (use_sni ? server_address : NULL));
202 if (result != STATE_OK) {
203 printf (_("CRITICAL - Cannot create SSL context.\n"));
204 close(sd);
205 np_net_ssl_cleanup();
206 return STATE_CRITICAL;
207 } else {
208 ssl_established = 1;
209 }
210 }
211#endif
185 212
186 /* watch for the SMTP connection string and */ 213 /* watch for the SMTP connection string and */
187 /* return a WARNING status if we couldn't read any data */ 214 /* return a WARNING status if we couldn't read any data */
@@ -189,44 +216,32 @@ main (int argc, char **argv)
189 printf (_("recv() failed\n")); 216 printf (_("recv() failed\n"));
190 return STATE_WARNING; 217 return STATE_WARNING;
191 } 218 }
192 else { 219
193 if (verbose) 220 /* save connect return (220 hostname ..) for later use */
194 printf ("%s", buffer); 221 xasprintf(&server_response, "%s", buffer);
195 /* strip the buffer of carriage returns */
196 strip (buffer);
197 /* make sure we find the response we are looking for */
198 if (!strstr (buffer, server_expect)) {
199 if (server_port == SMTP_PORT)
200 printf (_("Invalid SMTP response received from host: %s\n"), buffer);
201 else
202 printf (_("Invalid SMTP response received from host on port %d: %s\n"),
203 server_port, buffer);
204 return STATE_WARNING;
205 }
206 }
207 222
208 /* send the HELO/EHLO command */ 223 /* send the HELO/EHLO command */
209 send(sd, helocmd, strlen(helocmd), 0); 224 my_send(helocmd, strlen(helocmd));
210 225
211 /* allow for response to helo command to reach us */ 226 /* allow for response to helo command to reach us */
212 if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) { 227 if (recvlines(buffer, MAX_INPUT_BUFFER) <= 0) {
213 printf (_("recv() failed\n")); 228 printf (_("recv() failed\n"));
214 return STATE_WARNING; 229 return STATE_WARNING;
215 } else if(use_ehlo){ 230 } else if(use_ehlo || use_lhlo){
216 if(strstr(buffer, "250 STARTTLS") != NULL || 231 if(strstr(buffer, "250 STARTTLS") != NULL ||
217 strstr(buffer, "250-STARTTLS") != NULL){ 232 strstr(buffer, "250-STARTTLS") != NULL){
218 supports_tls=TRUE; 233 supports_tls=TRUE;
219 } 234 }
220 } 235 }
221 236
222 if(use_ssl && ! supports_tls){ 237 if(use_starttls && ! supports_tls){
223 printf(_("WARNING - TLS not supported by server\n")); 238 printf(_("WARNING - TLS not supported by server\n"));
224 smtp_quit(); 239 smtp_quit();
225 return STATE_WARNING; 240 return STATE_WARNING;
226 } 241 }
227 242
228#ifdef HAVE_SSL 243#ifdef HAVE_SSL
229 if(use_ssl) { 244 if(use_starttls) {
230 /* send the STARTTLS command */ 245 /* send the STARTTLS command */
231 send(sd, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0); 246 send(sd, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0);
232 247
@@ -236,11 +251,11 @@ main (int argc, char **argv)
236 smtp_quit(); 251 smtp_quit();
237 return STATE_UNKNOWN; 252 return STATE_UNKNOWN;
238 } 253 }
239 result = np_net_ssl_init(sd); 254 result = np_net_ssl_init_with_hostname(sd, (use_sni ? server_address : NULL));
240 if(result != STATE_OK) { 255 if(result != STATE_OK) {
241 printf (_("CRITICAL - Cannot create SSL context.\n")); 256 printf (_("CRITICAL - Cannot create SSL context.\n"));
242 np_net_ssl_cleanup();
243 close(sd); 257 close(sd);
258 np_net_ssl_cleanup();
244 return STATE_CRITICAL; 259 return STATE_CRITICAL;
245 } else { 260 } else {
246 ssl_established = 1; 261 ssl_established = 1;
@@ -284,12 +299,31 @@ main (int argc, char **argv)
284 } 299 }
285#endif 300#endif
286 301
302 if (verbose)
303 printf ("%s", buffer);
304
305 /* save buffer for later use */
306 xasprintf(&server_response, "%s%s", server_response, buffer);
307 /* strip the buffer of carriage returns */
308 strip (server_response);
309
310 /* make sure we find the droids we are looking for */
311 if (!strstr (server_response, server_expect)) {
312 if (server_port == SMTP_PORT)
313 printf (_("Invalid SMTP response received from host: %s\n"), server_response);
314 else
315 printf (_("Invalid SMTP response received from host on port %d: %s\n"),
316 server_port, server_response);
317 return STATE_WARNING;
318 }
319
287 if (send_mail_from) { 320 if (send_mail_from) {
288 my_send(cmd_str, strlen(cmd_str)); 321 my_send(cmd_str, strlen(cmd_str));
289 if (recvlines(buffer, MAX_INPUT_BUFFER) >= 1 && verbose) 322 if (recvlines(buffer, MAX_INPUT_BUFFER) >= 1 && verbose)
290 printf("%s", buffer); 323 printf("%s", buffer);
291 } 324 }
292 325
326 n = 0;
293 while (n < ncommands) { 327 while (n < ncommands) {
294 xasprintf (&cmd_str, "%s%s", commands[n], "\r\n"); 328 xasprintf (&cmd_str, "%s%s", commands[n], "\r\n");
295 my_send(cmd_str, strlen(cmd_str)); 329 my_send(cmd_str, strlen(cmd_str));
@@ -446,6 +480,10 @@ process_arguments (int argc, char **argv)
446 int c; 480 int c;
447 char* temp; 481 char* temp;
448 482
483 enum {
484 SNI_OPTION
485 };
486
449 int option = 0; 487 int option = 0;
450 static struct option longopts[] = { 488 static struct option longopts[] = {
451 {"hostname", required_argument, 0, 'H'}, 489 {"hostname", required_argument, 0, 'H'},
@@ -466,9 +504,14 @@ process_arguments (int argc, char **argv)
466 {"use-ipv4", no_argument, 0, '4'}, 504 {"use-ipv4", no_argument, 0, '4'},
467 {"use-ipv6", no_argument, 0, '6'}, 505 {"use-ipv6", no_argument, 0, '6'},
468 {"help", no_argument, 0, 'h'}, 506 {"help", no_argument, 0, 'h'},
507 {"lmtp", no_argument, 0, 'L'},
508 {"ssl", no_argument, 0, 's'},
509 {"tls", no_argument, 0, 's'},
469 {"starttls",no_argument,0,'S'}, 510 {"starttls",no_argument,0,'S'},
511 {"sni", no_argument, 0, SNI_OPTION},
470 {"certificate",required_argument,0,'D'}, 512 {"certificate",required_argument,0,'D'},
471 {"ignore-quit-failure",no_argument,0,'q'}, 513 {"ignore-quit-failure",no_argument,0,'q'},
514 {"proxy",no_argument,0,'r'},
472 {0, 0, 0, 0} 515 {0, 0, 0, 0}
473 }; 516 };
474 517
@@ -485,7 +528,7 @@ process_arguments (int argc, char **argv)
485 } 528 }
486 529
487 while (1) { 530 while (1) {
488 c = getopt_long (argc, argv, "+hVv46t:p:f:e:c:w:H:C:R:SD:F:A:U:P:q", 531 c = getopt_long (argc, argv, "+hVv46Lrt:p:f:e:c:w:H:C:R:sSD:F:A:U:P:q",
489 longopts, &option); 532 longopts, &option);
490 533
491 if (c == -1 || c == EOF) 534 if (c == -1 || c == EOF)
@@ -502,7 +545,7 @@ process_arguments (int argc, char **argv)
502 break; 545 break;
503 case 'p': /* port */ 546 case 'p': /* port */
504 if (is_intpos (optarg)) 547 if (is_intpos (optarg))
505 server_port = atoi (optarg); 548 server_port_option = atoi (optarg);
506 else 549 else
507 usage4 (_("Port must be a positive integer")); 550 usage4 (_("Port must be a positive integer"));
508 break; 551 break;
@@ -607,11 +650,29 @@ process_arguments (int argc, char **argv)
607#else 650#else
608 usage (_("SSL support not available - install OpenSSL and recompile")); 651 usage (_("SSL support not available - install OpenSSL and recompile"));
609#endif 652#endif
653 case 's':
654 /* ssl */
655 use_ssl = TRUE;
656 server_port = SMTPS_PORT;
657 break;
610 case 'S': 658 case 'S':
611 /* starttls */ 659 /* starttls */
612 use_ssl = TRUE; 660 use_starttls = TRUE;
613 use_ehlo = TRUE; 661 use_ehlo = TRUE;
614 break; 662 break;
663 case SNI_OPTION:
664#ifdef HAVE_SSL
665 use_sni = TRUE;
666#else
667 usage (_("SSL support not available - install OpenSSL and recompile"));
668#endif
669 break;
670 case 'r':
671 use_proxy_prefix = TRUE;
672 break;
673 case 'L':
674 use_lhlo = TRUE;
675 break;
615 case '4': 676 case '4':
616 address_family = AF_INET; 677 address_family = AF_INET;
617 break; 678 break;
@@ -655,6 +716,14 @@ process_arguments (int argc, char **argv)
655 if (from_arg==NULL) 716 if (from_arg==NULL)
656 from_arg = strdup(" "); 717 from_arg = strdup(" ");
657 718
719 if (use_starttls && use_ssl) {
720 usage4 (_("Set either -s/--ssl/--tls or -S/--starttls"));
721 }
722
723 if (server_port_option != 0) {
724 server_port = server_port_option;
725 }
726
658 return validate_arguments (); 727 return validate_arguments ();
659} 728}
660 729
@@ -764,10 +833,12 @@ recvlines(char *buf, size_t bufsize)
764int 833int
765my_close (void) 834my_close (void)
766{ 835{
836 int result;
837 result = close(sd);
767#ifdef HAVE_SSL 838#ifdef HAVE_SSL
768 np_net_ssl_cleanup(); 839 np_net_ssl_cleanup();
769#endif 840#endif
770 return close(sd); 841 return result;
771} 842}
772 843
773 844
@@ -805,11 +876,18 @@ print_help (void)
805 printf (" %s\n", _("FROM-address to include in MAIL command, required by Exchange 2000")), 876 printf (" %s\n", _("FROM-address to include in MAIL command, required by Exchange 2000")),
806 printf (" %s\n", "-F, --fqdn=STRING"); 877 printf (" %s\n", "-F, --fqdn=STRING");
807 printf (" %s\n", _("FQDN used for HELO")); 878 printf (" %s\n", _("FQDN used for HELO"));
879 printf (" %s\n", "-r, --proxy");
880 printf (" %s\n", _("Use PROXY protocol prefix for the connection."));
808#ifdef HAVE_SSL 881#ifdef HAVE_SSL
809 printf (" %s\n", "-D, --certificate=INTEGER[,INTEGER]"); 882 printf (" %s\n", "-D, --certificate=INTEGER[,INTEGER]");
810 printf (" %s\n", _("Minimum number of days a certificate has to be valid.")); 883 printf (" %s\n", _("Minimum number of days a certificate has to be valid."));
884 printf (" %s\n", "-s, --ssl, --tls");
885 printf (" %s\n", _("Use SSL/TLS for the connection."));
886 printf (_(" Sets default port to %d.\n"), SMTPS_PORT);
811 printf (" %s\n", "-S, --starttls"); 887 printf (" %s\n", "-S, --starttls");
812 printf (" %s\n", _("Use STARTTLS for the connection.")); 888 printf (" %s\n", _("Use STARTTLS for the connection."));
889 printf (" %s\n", "--sni");
890 printf (" %s\n", _("Enable SSL/TLS hostname extension support (SNI)"));
813#endif 891#endif
814 892
815 printf (" %s\n", "-A, --authtype=STRING"); 893 printf (" %s\n", "-A, --authtype=STRING");
@@ -818,6 +896,8 @@ print_help (void)
818 printf (" %s\n", _("SMTP AUTH username")); 896 printf (" %s\n", _("SMTP AUTH username"));
819 printf (" %s\n", "-P, --authpass=STRING"); 897 printf (" %s\n", "-P, --authpass=STRING");
820 printf (" %s\n", _("SMTP AUTH password")); 898 printf (" %s\n", _("SMTP AUTH password"));
899 printf (" %s\n", "-L, --lmtp");
900 printf (" %s\n", _("Send LHLO instead of HELO/EHLO"));
821 printf (" %s\n", "-q, --ignore-quit-failure"); 901 printf (" %s\n", "-q, --ignore-quit-failure");
822 printf (" %s\n", _("Ignore failure when sending QUIT command to server")); 902 printf (" %s\n", _("Ignore failure when sending QUIT command to server"));
823 903
@@ -828,9 +908,9 @@ print_help (void)
828 printf (UT_VERBOSE); 908 printf (UT_VERBOSE);
829 909
830 printf("\n"); 910 printf("\n");
831 printf ("%s\n", _("Successul connects return STATE_OK, refusals and timeouts return")); 911 printf ("%s\n", _("Successful connects return STATE_OK, refusals and timeouts return"));
832 printf ("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful")); 912 printf ("%s\n", _("STATE_CRITICAL, other errors return STATE_UNKNOWN. Successful"));
833 printf ("%s\n", _("connects, but incorrect reponse messages from the host result in")); 913 printf ("%s\n", _("connects, but incorrect response messages from the host result in"));
834 printf ("%s\n", _("STATE_WARNING return values.")); 914 printf ("%s\n", _("STATE_WARNING return values."));
835 915
836 printf (UT_SUPPORT); 916 printf (UT_SUPPORT);
@@ -844,6 +924,6 @@ print_usage (void)
844 printf ("%s\n", _("Usage:")); 924 printf ("%s\n", _("Usage:"));
845 printf ("%s -H host [-p port] [-4|-6] [-e expect] [-C command] [-R response] [-f from addr]\n", progname); 925 printf ("%s -H host [-p port] [-4|-6] [-e expect] [-C command] [-R response] [-f from addr]\n", progname);
846 printf ("[-A authtype -U authuser -P authpass] [-w warn] [-c crit] [-t timeout] [-q]\n"); 926 printf ("[-A authtype -U authuser -P authpass] [-w warn] [-c crit] [-t timeout] [-q]\n");
847 printf ("[-F fqdn] [-S] [-D warn days cert expire[,crit days cert expire]] [-v] \n"); 927 printf ("[-F fqdn] [-S] [-L] [-D warn days cert expire[,crit days cert expire]] [-r] [--sni] [-v] \n");
848} 928}
849 929