diff options
| -rw-r--r-- | plugins/check_smtp.c | 766 | ||||
| -rw-r--r-- | plugins/check_smtp.d/config.h | 28 | ||||
| -rw-r--r-- | plugins/netutils.h | 20 | ||||
| -rw-r--r-- | plugins/sslutils.c | 132 | ||||
| -rw-r--r-- | plugins/t/check_smtp.t | 7 |
5 files changed, 624 insertions, 329 deletions
diff --git a/plugins/check_smtp.c b/plugins/check_smtp.c index 83ad575c..e806ad29 100644 --- a/plugins/check_smtp.c +++ b/plugins/check_smtp.c | |||
| @@ -28,20 +28,25 @@ | |||
| 28 | * | 28 | * |
| 29 | *****************************************************************************/ | 29 | *****************************************************************************/ |
| 30 | 30 | ||
| 31 | const char *progname = "check_smtp"; | ||
| 32 | const char *copyright = "2000-2024"; | ||
| 33 | const char *email = "devel@monitoring-plugins.org"; | ||
| 34 | |||
| 35 | #include "common.h" | 31 | #include "common.h" |
| 36 | #include "netutils.h" | 32 | #include "netutils.h" |
| 33 | #include "output.h" | ||
| 34 | #include "perfdata.h" | ||
| 35 | #include "thresholds.h" | ||
| 37 | #include "utils.h" | 36 | #include "utils.h" |
| 38 | #include "base64.h" | 37 | #include "base64.h" |
| 39 | #include "regex.h" | 38 | #include "regex.h" |
| 40 | 39 | ||
| 40 | #include <bits/getopt_ext.h> | ||
| 41 | #include <ctype.h> | 41 | #include <ctype.h> |
| 42 | #include <string.h> | ||
| 42 | #include "check_smtp.d/config.h" | 43 | #include "check_smtp.d/config.h" |
| 43 | #include "../lib/states.h" | 44 | #include "../lib/states.h" |
| 44 | 45 | ||
| 46 | const char *progname = "check_smtp"; | ||
| 47 | const char *copyright = "2000-2024"; | ||
| 48 | const char *email = "devel@monitoring-plugins.org"; | ||
| 49 | |||
| 45 | #define PROXY_PREFIX "PROXY TCP4 0.0.0.0 0.0.0.0 25 25\r\n" | 50 | #define PROXY_PREFIX "PROXY TCP4 0.0.0.0 0.0.0.0 25 25\r\n" |
| 46 | #define SMTP_HELO "HELO " | 51 | #define SMTP_HELO "HELO " |
| 47 | #define SMTP_EHLO "EHLO " | 52 | #define SMTP_EHLO "EHLO " |
| @@ -111,6 +116,10 @@ int main(int argc, char **argv) { | |||
| 111 | 116 | ||
| 112 | const check_smtp_config config = tmp_config.config; | 117 | const check_smtp_config config = tmp_config.config; |
| 113 | 118 | ||
| 119 | if (config.output_format_is_set) { | ||
| 120 | mp_set_format(config.output_format); | ||
| 121 | } | ||
| 122 | |||
| 114 | /* If localhostname not set on command line, use gethostname to set */ | 123 | /* If localhostname not set on command line, use gethostname to set */ |
| 115 | char *localhostname = config.localhostname; | 124 | char *localhostname = config.localhostname; |
| 116 | if (!localhostname) { | 125 | if (!localhostname) { |
| @@ -161,359 +170,459 @@ int main(int argc, char **argv) { | |||
| 161 | gettimeofday(&start_time, NULL); | 170 | gettimeofday(&start_time, NULL); |
| 162 | 171 | ||
| 163 | int socket_descriptor = 0; | 172 | int socket_descriptor = 0; |
| 173 | |||
| 164 | /* try to connect to the host at the given port number */ | 174 | /* try to connect to the host at the given port number */ |
| 165 | mp_state_enum result = | 175 | mp_state_enum tcp_result = |
| 166 | my_tcp_connect(config.server_address, config.server_port, &socket_descriptor); | 176 | my_tcp_connect(config.server_address, config.server_port, &socket_descriptor); |
| 167 | 177 | ||
| 168 | char *error_msg = ""; | 178 | mp_check overall = mp_check_init(); |
| 179 | mp_subcheck sc_tcp_connect = mp_subcheck_init(); | ||
| 169 | char buffer[MAX_INPUT_BUFFER]; | 180 | char buffer[MAX_INPUT_BUFFER]; |
| 170 | bool ssl_established = false; | 181 | bool ssl_established = false; |
| 171 | if (result == STATE_OK) { /* we connected */ | 182 | |
| 172 | /* If requested, send PROXY header */ | 183 | if (tcp_result != STATE_OK) { |
| 173 | if (config.use_proxy_prefix) { | 184 | // Connect failed |
| 174 | if (verbose) { | 185 | sc_tcp_connect = mp_set_subcheck_state(sc_tcp_connect, STATE_CRITICAL); |
| 175 | printf("Sending header %s\n", PROXY_PREFIX); | 186 | xasprintf(&sc_tcp_connect.output, "TCP connect to '%s' failed", config.server_address); |
| 176 | } | 187 | mp_add_subcheck_to_check(&overall, sc_tcp_connect); |
| 177 | my_send(config, PROXY_PREFIX, strlen(PROXY_PREFIX), socket_descriptor, ssl_established); | 188 | mp_exit(overall); |
| 189 | } | ||
| 190 | |||
| 191 | /* we connected */ | ||
| 192 | /* If requested, send PROXY header */ | ||
| 193 | if (config.use_proxy_prefix) { | ||
| 194 | if (verbose) { | ||
| 195 | printf("Sending header %s\n", PROXY_PREFIX); | ||
| 178 | } | 196 | } |
| 197 | my_send(config, PROXY_PREFIX, strlen(PROXY_PREFIX), socket_descriptor, ssl_established); | ||
| 198 | } | ||
| 179 | 199 | ||
| 180 | #ifdef HAVE_SSL | 200 | #ifdef HAVE_SSL |
| 181 | if (config.use_ssl) { | 201 | if (config.use_ssl) { |
| 182 | result = np_net_ssl_init_with_hostname(socket_descriptor, | 202 | int tls_result = np_net_ssl_init_with_hostname( |
| 183 | (config.use_sni ? config.server_address : NULL)); | 203 | socket_descriptor, (config.use_sni ? config.server_address : NULL)); |
| 184 | if (result != STATE_OK) { | 204 | |
| 185 | printf(_("CRITICAL - Cannot create SSL context.\n")); | 205 | mp_subcheck sc_tls_connection = mp_subcheck_init(); |
| 186 | close(socket_descriptor); | 206 | |
| 187 | np_net_ssl_cleanup(); | 207 | if (tls_result != STATE_OK) { |
| 188 | exit(STATE_CRITICAL); | 208 | close(socket_descriptor); |
| 189 | } | 209 | np_net_ssl_cleanup(); |
| 190 | ssl_established = true; | 210 | |
| 211 | sc_tls_connection = mp_set_subcheck_state(sc_tls_connection, STATE_CRITICAL); | ||
| 212 | xasprintf(&sc_tls_connection.output, "cannot create TLS context"); | ||
| 213 | mp_add_subcheck_to_check(&overall, sc_tls_connection); | ||
| 214 | mp_exit(overall); | ||
| 191 | } | 215 | } |
| 216 | |||
| 217 | sc_tls_connection = mp_set_subcheck_state(sc_tls_connection, STATE_OK); | ||
| 218 | xasprintf(&sc_tls_connection.output, "TLS context established"); | ||
| 219 | mp_add_subcheck_to_check(&overall, sc_tls_connection); | ||
| 220 | ssl_established = true; | ||
| 221 | } | ||
| 192 | #endif | 222 | #endif |
| 193 | 223 | ||
| 194 | /* watch for the SMTP connection string and */ | 224 | /* watch for the SMTP connection string and */ |
| 195 | /* return a WARNING status if we couldn't read any data */ | 225 | /* return a WARNING status if we couldn't read any data */ |
| 196 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) { | 226 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) { |
| 197 | printf(_("recv() failed\n")); | 227 | mp_subcheck sc_read_data = mp_subcheck_init(); |
| 198 | exit(STATE_WARNING); | 228 | sc_read_data = mp_set_subcheck_state(sc_read_data, STATE_WARNING); |
| 199 | } | 229 | xasprintf(&sc_read_data.output, "recv() failed"); |
| 230 | mp_add_subcheck_to_check(&overall, sc_read_data); | ||
| 231 | mp_exit(overall); | ||
| 232 | } | ||
| 200 | 233 | ||
| 201 | char *server_response = NULL; | 234 | char *server_response = NULL; |
| 202 | /* save connect return (220 hostname ..) for later use */ | 235 | /* save connect return (220 hostname ..) for later use */ |
| 203 | xasprintf(&server_response, "%s", buffer); | 236 | xasprintf(&server_response, "%s", buffer); |
| 204 | 237 | ||
| 205 | /* send the HELO/EHLO command */ | 238 | /* send the HELO/EHLO command */ |
| 206 | my_send(config, helocmd, (int)strlen(helocmd), socket_descriptor, ssl_established); | 239 | my_send(config, helocmd, (int)strlen(helocmd), socket_descriptor, ssl_established); |
| 207 | 240 | ||
| 208 | /* allow for response to helo command to reach us */ | 241 | /* allow for response to helo command to reach us */ |
| 209 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) { | 242 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) { |
| 210 | printf(_("recv() failed\n")); | 243 | mp_subcheck sc_read_data = mp_subcheck_init(); |
| 211 | exit(STATE_WARNING); | 244 | sc_read_data = mp_set_subcheck_state(sc_read_data, STATE_WARNING); |
| 212 | } | 245 | xasprintf(&sc_read_data.output, "recv() failed"); |
| 246 | mp_add_subcheck_to_check(&overall, sc_read_data); | ||
| 247 | mp_exit(overall); | ||
| 248 | } | ||
| 213 | 249 | ||
| 214 | bool supports_tls = false; | 250 | bool supports_tls = false; |
| 215 | if (config.use_ehlo || config.use_lhlo) { | 251 | if (config.use_ehlo || config.use_lhlo) { |
| 216 | if (strstr(buffer, "250 STARTTLS") != NULL || strstr(buffer, "250-STARTTLS") != NULL) { | 252 | if (strstr(buffer, "250 STARTTLS") != NULL || strstr(buffer, "250-STARTTLS") != NULL) { |
| 217 | supports_tls = true; | 253 | supports_tls = true; |
| 218 | } | ||
| 219 | } | 254 | } |
| 255 | } | ||
| 220 | 256 | ||
| 221 | if (config.use_starttls && !supports_tls) { | 257 | if (config.use_starttls && !supports_tls) { |
| 222 | printf(_("WARNING - TLS not supported by server\n")); | 258 | smtp_quit(config, buffer, socket_descriptor, ssl_established); |
| 259 | |||
| 260 | mp_subcheck sc_read_data = mp_subcheck_init(); | ||
| 261 | sc_read_data = mp_set_subcheck_state(sc_read_data, STATE_WARNING); | ||
| 262 | xasprintf(&sc_read_data.output, "StartTLS not supported by server"); | ||
| 263 | mp_add_subcheck_to_check(&overall, sc_read_data); | ||
| 264 | mp_exit(overall); | ||
| 265 | } | ||
| 266 | |||
| 267 | #ifdef HAVE_SSL | ||
| 268 | if (config.use_starttls) { | ||
| 269 | /* send the STARTTLS command */ | ||
| 270 | send(socket_descriptor, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0); | ||
| 271 | |||
| 272 | mp_subcheck sc_starttls_init = mp_subcheck_init(); | ||
| 273 | recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, | ||
| 274 | ssl_established); /* wait for it */ | ||
| 275 | if (!strstr(buffer, SMTP_EXPECT)) { | ||
| 223 | smtp_quit(config, buffer, socket_descriptor, ssl_established); | 276 | smtp_quit(config, buffer, socket_descriptor, ssl_established); |
| 224 | exit(STATE_WARNING); | 277 | |
| 278 | xasprintf(&sc_starttls_init.output, "StartTLS not supported by server"); | ||
| 279 | sc_starttls_init = mp_set_subcheck_state(sc_starttls_init, STATE_UNKNOWN); | ||
| 280 | mp_add_subcheck_to_check(&overall, sc_starttls_init); | ||
| 281 | mp_exit(overall); | ||
| 225 | } | 282 | } |
| 226 | 283 | ||
| 227 | #ifdef HAVE_SSL | 284 | mp_state_enum starttls_result = np_net_ssl_init_with_hostname( |
| 228 | if (config.use_starttls) { | 285 | socket_descriptor, (config.use_sni ? config.server_address : NULL)); |
| 229 | /* send the STARTTLS command */ | 286 | if (starttls_result != STATE_OK) { |
| 230 | send(socket_descriptor, SMTP_STARTTLS, strlen(SMTP_STARTTLS), 0); | 287 | close(socket_descriptor); |
| 231 | 288 | np_net_ssl_cleanup(); | |
| 232 | recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, | ||
| 233 | ssl_established); /* wait for it */ | ||
| 234 | if (!strstr(buffer, SMTP_EXPECT)) { | ||
| 235 | printf(_("Server does not support STARTTLS\n")); | ||
| 236 | smtp_quit(config, buffer, socket_descriptor, ssl_established); | ||
| 237 | exit(STATE_UNKNOWN); | ||
| 238 | } | ||
| 239 | 289 | ||
| 240 | result = np_net_ssl_init_with_hostname(socket_descriptor, | 290 | sc_starttls_init = mp_set_subcheck_state(sc_starttls_init, STATE_CRITICAL); |
| 241 | (config.use_sni ? config.server_address : NULL)); | 291 | xasprintf(&sc_starttls_init.output, "failed to create StartTLS context"); |
| 242 | if (result != STATE_OK) { | 292 | mp_add_subcheck_to_check(&overall, sc_starttls_init); |
| 243 | printf(_("CRITICAL - Cannot create SSL context.\n")); | 293 | mp_exit(overall); |
| 244 | close(socket_descriptor); | 294 | } |
| 245 | np_net_ssl_cleanup(); | 295 | sc_starttls_init = mp_set_subcheck_state(sc_starttls_init, STATE_OK); |
| 246 | exit(STATE_CRITICAL); | 296 | xasprintf(&sc_starttls_init.output, "created StartTLS context"); |
| 247 | } | 297 | mp_add_subcheck_to_check(&overall, sc_starttls_init); |
| 298 | |||
| 299 | ssl_established = true; | ||
| 300 | |||
| 301 | /* | ||
| 302 | * Resend the EHLO command. | ||
| 303 | * | ||
| 304 | * RFC 3207 (4.2) says: ``The client MUST discard any knowledge | ||
| 305 | * obtained from the server, such as the list of SMTP service | ||
| 306 | * extensions, which was not obtained from the TLS negotiation | ||
| 307 | * itself. The client SHOULD send an EHLO command as the first | ||
| 308 | * command after a successful TLS negotiation.'' For this | ||
| 309 | * reason, some MTAs will not allow an AUTH LOGIN command before | ||
| 310 | * we resent EHLO via TLS. | ||
| 311 | */ | ||
| 312 | if (my_send(config, helocmd, (int)strlen(helocmd), socket_descriptor, ssl_established) <= | ||
| 313 | 0) { | ||
| 314 | my_close(socket_descriptor); | ||
| 315 | |||
| 316 | mp_subcheck sc_ehlo = mp_subcheck_init(); | ||
| 317 | sc_ehlo = mp_set_subcheck_state(sc_ehlo, STATE_UNKNOWN); | ||
| 318 | xasprintf(&sc_ehlo.output, "cannot send EHLO command via StartTLS"); | ||
| 319 | mp_add_subcheck_to_check(&overall, sc_ehlo); | ||
| 320 | mp_exit(overall); | ||
| 321 | } | ||
| 248 | 322 | ||
| 249 | ssl_established = true; | 323 | if (verbose) { |
| 250 | 324 | printf(_("sent %s"), helocmd); | |
| 251 | /* | 325 | } |
| 252 | * Resend the EHLO command. | ||
| 253 | * | ||
| 254 | * RFC 3207 (4.2) says: ``The client MUST discard any knowledge | ||
| 255 | * obtained from the server, such as the list of SMTP service | ||
| 256 | * extensions, which was not obtained from the TLS negotiation | ||
| 257 | * itself. The client SHOULD send an EHLO command as the first | ||
| 258 | * command after a successful TLS negotiation.'' For this | ||
| 259 | * reason, some MTAs will not allow an AUTH LOGIN command before | ||
| 260 | * we resent EHLO via TLS. | ||
| 261 | */ | ||
| 262 | if (my_send(config, helocmd, strlen(helocmd), socket_descriptor, ssl_established) <= | ||
| 263 | 0) { | ||
| 264 | printf("%s\n", _("SMTP UNKNOWN - Cannot send EHLO command via TLS.")); | ||
| 265 | my_close(socket_descriptor); | ||
| 266 | exit(STATE_UNKNOWN); | ||
| 267 | } | ||
| 268 | 326 | ||
| 269 | if (verbose) { | 327 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= 0) { |
| 270 | printf(_("sent %s"), helocmd); | 328 | my_close(socket_descriptor); |
| 271 | } | ||
| 272 | 329 | ||
| 273 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) <= | 330 | mp_subcheck sc_ehlo = mp_subcheck_init(); |
| 274 | 0) { | 331 | sc_ehlo = mp_set_subcheck_state(sc_ehlo, STATE_UNKNOWN); |
| 275 | printf("%s\n", _("SMTP UNKNOWN - Cannot read EHLO response via TLS.")); | 332 | xasprintf(&sc_ehlo.output, "cannot read EHLO response via StartTLS"); |
| 276 | my_close(socket_descriptor); | 333 | mp_add_subcheck_to_check(&overall, sc_ehlo); |
| 277 | exit(STATE_UNKNOWN); | 334 | mp_exit(overall); |
| 278 | } | 335 | } |
| 279 | 336 | ||
| 280 | if (verbose) { | 337 | if (verbose) { |
| 281 | printf("%s", buffer); | 338 | printf("%s", buffer); |
| 282 | } | 339 | } |
| 340 | } | ||
| 283 | 341 | ||
| 284 | # ifdef USE_OPENSSL | 342 | # ifdef USE_OPENSSL |
| 285 | if (config.check_cert) { | 343 | if (ssl_established) { |
| 286 | result = | 344 | net_ssl_check_cert_result cert_check_result = |
| 287 | np_net_ssl_check_cert(config.days_till_exp_warn, config.days_till_exp_crit); | 345 | np_net_ssl_check_cert2(config.days_till_exp_warn, config.days_till_exp_crit); |
| 288 | smtp_quit(config, buffer, socket_descriptor, ssl_established); | 346 | |
| 289 | my_close(socket_descriptor); | 347 | mp_subcheck sc_cert_check = mp_subcheck_init(); |
| 290 | exit(result); | 348 | |
| 349 | switch (cert_check_result.errors) { | ||
| 350 | case ALL_OK: { | ||
| 351 | |||
| 352 | if (cert_check_result.result_state != STATE_OK && | ||
| 353 | config.ignore_certificate_expiration) { | ||
| 354 | xasprintf(&sc_cert_check.output, | ||
| 355 | "Remaining certificate lifetime: %d days. Expiration will be ignored", | ||
| 356 | (int)(cert_check_result.remaining_seconds / 86400)); | ||
| 357 | sc_cert_check = mp_set_subcheck_state(sc_cert_check, STATE_OK); | ||
| 358 | } else { | ||
| 359 | xasprintf(&sc_cert_check.output, "Remaining certificate lifetime: %d days", | ||
| 360 | (int)(cert_check_result.remaining_seconds / 86400)); | ||
| 361 | sc_cert_check = | ||
| 362 | mp_set_subcheck_state(sc_cert_check, cert_check_result.result_state); | ||
| 291 | } | 363 | } |
| 364 | } break; | ||
| 365 | case NO_SERVER_CERTIFICATE_PRESENT: { | ||
| 366 | xasprintf(&sc_cert_check.output, "no server certificate present"); | ||
| 367 | sc_cert_check = mp_set_subcheck_state(sc_cert_check, cert_check_result.result_state); | ||
| 368 | } break; | ||
| 369 | case UNABLE_TO_RETRIEVE_CERTIFICATE_SUBJECT: { | ||
| 370 | xasprintf(&sc_cert_check.output, "can not retrieve certificate subject"); | ||
| 371 | sc_cert_check = mp_set_subcheck_state(sc_cert_check, cert_check_result.result_state); | ||
| 372 | } break; | ||
| 373 | case WRONG_TIME_FORMAT_IN_CERTIFICATE: { | ||
| 374 | xasprintf(&sc_cert_check.output, "wrong time format in certificate"); | ||
| 375 | sc_cert_check = mp_set_subcheck_state(sc_cert_check, cert_check_result.result_state); | ||
| 376 | } break; | ||
| 377 | }; | ||
| 378 | |||
| 379 | mp_add_subcheck_to_check(&overall, sc_cert_check); | ||
| 380 | } | ||
| 292 | # endif /* USE_OPENSSL */ | 381 | # endif /* USE_OPENSSL */ |
| 293 | } | 382 | |
| 294 | #endif | 383 | #endif |
| 295 | 384 | ||
| 296 | if (verbose) { | 385 | if (verbose) { |
| 386 | printf("%s", buffer); | ||
| 387 | } | ||
| 388 | |||
| 389 | /* save buffer for later use */ | ||
| 390 | xasprintf(&server_response, "%s%s", server_response, buffer); | ||
| 391 | /* strip the buffer of carriage returns */ | ||
| 392 | strip(server_response); | ||
| 393 | |||
| 394 | /* make sure we find the droids we are looking for */ | ||
| 395 | mp_subcheck sc_expect_response = mp_subcheck_init(); | ||
| 396 | |||
| 397 | if (!strstr(server_response, config.server_expect)) { | ||
| 398 | sc_expect_response = mp_set_subcheck_state(sc_expect_response, STATE_WARNING); | ||
| 399 | if (config.server_port == SMTP_PORT) { | ||
| 400 | xasprintf(&sc_expect_response.output, _("invalid SMTP response received from host: %s"), | ||
| 401 | server_response); | ||
| 402 | } else { | ||
| 403 | xasprintf(&sc_expect_response.output, | ||
| 404 | _("invalid SMTP response received from host on port %d: %s"), | ||
| 405 | config.server_port, server_response); | ||
| 406 | } | ||
| 407 | exit(STATE_WARNING); | ||
| 408 | } else { | ||
| 409 | xasprintf(&sc_expect_response.output, "received valid SMTP response '%s' from host: '%s'", | ||
| 410 | config.server_expect, server_response); | ||
| 411 | sc_expect_response = mp_set_subcheck_state(sc_expect_response, STATE_OK); | ||
| 412 | } | ||
| 413 | |||
| 414 | mp_add_subcheck_to_check(&overall, sc_expect_response); | ||
| 415 | |||
| 416 | if (config.send_mail_from) { | ||
| 417 | my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established); | ||
| 418 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= 1 && | ||
| 419 | verbose) { | ||
| 297 | printf("%s", buffer); | 420 | printf("%s", buffer); |
| 298 | } | 421 | } |
| 422 | } | ||
| 299 | 423 | ||
| 300 | /* save buffer for later use */ | 424 | size_t counter = 0; |
| 301 | xasprintf(&server_response, "%s%s", server_response, buffer); | 425 | while (counter < config.ncommands) { |
| 302 | /* strip the buffer of carriage returns */ | 426 | xasprintf(&cmd_str, "%s%s", config.commands[counter], "\r\n"); |
| 303 | strip(server_response); | 427 | my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established); |
| 428 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= 1 && | ||
| 429 | verbose) { | ||
| 430 | printf("%s", buffer); | ||
| 431 | } | ||
| 304 | 432 | ||
| 305 | /* make sure we find the droids we are looking for */ | 433 | strip(buffer); |
| 306 | if (!strstr(server_response, config.server_expect)) { | 434 | |
| 307 | if (config.server_port == SMTP_PORT) { | 435 | if (counter < config.nresponses) { |
| 308 | printf(_("Invalid SMTP response received from host: %s\n"), server_response); | 436 | int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE; |
| 309 | } else { | 437 | regex_t preg; |
| 310 | printf(_("Invalid SMTP response received from host on port %d: %s\n"), | 438 | int errcode = regcomp(&preg, config.responses[counter], cflags); |
| 311 | config.server_port, server_response); | 439 | char errbuf[MAX_INPUT_BUFFER]; |
| 440 | if (errcode != 0) { | ||
| 441 | regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER); | ||
| 442 | printf(_("Could Not Compile Regular Expression")); | ||
| 443 | exit(STATE_UNKNOWN); | ||
| 312 | } | 444 | } |
| 313 | exit(STATE_WARNING); | ||
| 314 | } | ||
| 315 | 445 | ||
| 316 | if (config.send_mail_from) { | 446 | regmatch_t pmatch[10]; |
| 317 | my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established); | 447 | int eflags = 0; |
| 318 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= | 448 | int excode = regexec(&preg, buffer, 10, pmatch, eflags); |
| 319 | 1 && | 449 | mp_subcheck sc_expected_responses = mp_subcheck_init(); |
| 320 | verbose) { | 450 | if (excode == 0) { |
| 321 | printf("%s", buffer); | 451 | xasprintf(&sc_expected_responses.output, "valid response '%s' to command '%s'", |
| 452 | buffer, config.commands[counter]); | ||
| 453 | sc_expected_responses = mp_set_subcheck_state(sc_expected_responses, STATE_OK); | ||
| 454 | } else if (excode == REG_NOMATCH) { | ||
| 455 | sc_expected_responses = mp_set_subcheck_state(sc_expected_responses, STATE_WARNING); | ||
| 456 | xasprintf(&sc_expected_responses.output, "invalid response '%s' to command '%s'", | ||
| 457 | buffer, config.commands[counter]); | ||
| 458 | } else { | ||
| 459 | regerror(excode, &preg, errbuf, MAX_INPUT_BUFFER); | ||
| 460 | xasprintf(&sc_expected_responses.output, "regexec execute error: %s", errbuf); | ||
| 461 | sc_expected_responses = mp_set_subcheck_state(sc_expected_responses, STATE_UNKNOWN); | ||
| 322 | } | 462 | } |
| 323 | } | 463 | } |
| 464 | counter++; | ||
| 465 | } | ||
| 324 | 466 | ||
| 325 | int counter = 0; | 467 | if (config.authtype != NULL) { |
| 326 | while (counter < config.ncommands) { | 468 | mp_subcheck sc_auth = mp_subcheck_init(); |
| 327 | xasprintf(&cmd_str, "%s%s", config.commands[counter], "\r\n"); | 469 | |
| 328 | my_send(config, cmd_str, (int)strlen(cmd_str), socket_descriptor, ssl_established); | 470 | if (strcmp(config.authtype, "LOGIN") == 0) { |
| 329 | if (recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, ssl_established) >= | 471 | char *abuf; |
| 330 | 1 && | 472 | int ret; |
| 331 | verbose) { | 473 | do { |
| 332 | printf("%s", buffer); | 474 | /* send AUTH LOGIN */ |
| 333 | } | 475 | my_send(config, SMTP_AUTH_LOGIN, strlen(SMTP_AUTH_LOGIN), socket_descriptor, |
| 334 | strip(buffer); | 476 | ssl_established); |
| 335 | if (counter < config.nresponses) { | 477 | |
| 336 | int cflags = REG_EXTENDED | REG_NOSUB | REG_NEWLINE; | 478 | if (verbose) { |
| 337 | regex_t preg; | 479 | printf(_("sent %s\n"), "AUTH LOGIN"); |
| 338 | int errcode = regcomp(&preg, config.responses[counter], cflags); | ||
| 339 | char errbuf[MAX_INPUT_BUFFER]; | ||
| 340 | if (errcode != 0) { | ||
| 341 | regerror(errcode, &preg, errbuf, MAX_INPUT_BUFFER); | ||
| 342 | printf(_("Could Not Compile Regular Expression")); | ||
| 343 | exit(STATE_UNKNOWN); | ||
| 344 | } | 480 | } |
| 345 | 481 | ||
| 346 | regmatch_t pmatch[10]; | 482 | if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, |
| 347 | int eflags = 0; | 483 | ssl_established)) <= 0) { |
| 348 | int excode = regexec(&preg, buffer, 10, pmatch, eflags); | 484 | xasprintf(&sc_auth.output, _("recv() failed after AUTH LOGIN")); |
| 349 | if (excode == 0) { | 485 | sc_auth = mp_set_subcheck_state(sc_auth, STATE_WARNING); |
| 350 | result = STATE_OK; | 486 | break; |
| 351 | } else if (excode == REG_NOMATCH) { | ||
| 352 | result = STATE_WARNING; | ||
| 353 | printf(_("SMTP %s - Invalid response '%s' to command '%s'\n"), | ||
| 354 | state_text(result), buffer, config.commands[counter]); | ||
| 355 | } else { | ||
| 356 | regerror(excode, &preg, errbuf, MAX_INPUT_BUFFER); | ||
| 357 | printf(_("Execute Error: %s\n"), errbuf); | ||
| 358 | result = STATE_UNKNOWN; | ||
| 359 | } | 487 | } |
| 360 | } | ||
| 361 | counter++; | ||
| 362 | } | ||
| 363 | 488 | ||
| 364 | if (config.authtype != NULL) { | 489 | if (verbose) { |
| 365 | if (strcmp(config.authtype, "LOGIN") == 0) { | 490 | printf(_("received %s\n"), buffer); |
| 366 | char *abuf; | 491 | } |
| 367 | int ret; | 492 | |
| 368 | do { | 493 | if (strncmp(buffer, "334", 3) != 0) { |
| 369 | if (config.authuser == NULL) { | 494 | xasprintf(&sc_auth.output, "invalid response received after AUTH LOGIN"); |
| 370 | result = STATE_CRITICAL; | 495 | sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL); |
| 371 | xasprintf(&error_msg, _("no authuser specified, ")); | ||
| 372 | break; | ||
| 373 | } | ||
| 374 | if (config.authpass == NULL) { | ||
| 375 | result = STATE_CRITICAL; | ||
| 376 | xasprintf(&error_msg, _("no authpass specified, ")); | ||
| 377 | break; | ||
| 378 | } | ||
| 379 | |||
| 380 | /* send AUTH LOGIN */ | ||
| 381 | my_send(config, SMTP_AUTH_LOGIN, strlen(SMTP_AUTH_LOGIN), socket_descriptor, | ||
| 382 | ssl_established); | ||
| 383 | if (verbose) { | ||
| 384 | printf(_("sent %s\n"), "AUTH LOGIN"); | ||
| 385 | } | ||
| 386 | |||
| 387 | if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, | ||
| 388 | ssl_established)) <= 0) { | ||
| 389 | xasprintf(&error_msg, _("recv() failed after AUTH LOGIN, ")); | ||
| 390 | result = STATE_WARNING; | ||
| 391 | break; | ||
| 392 | } | ||
| 393 | if (verbose) { | ||
| 394 | printf(_("received %s\n"), buffer); | ||
| 395 | } | ||
| 396 | |||
| 397 | if (strncmp(buffer, "334", 3) != 0) { | ||
| 398 | result = STATE_CRITICAL; | ||
| 399 | xasprintf(&error_msg, _("invalid response received after AUTH LOGIN, ")); | ||
| 400 | break; | ||
| 401 | } | ||
| 402 | |||
| 403 | /* encode authuser with base64 */ | ||
| 404 | base64_encode_alloc(config.authuser, strlen(config.authuser), &abuf); | ||
| 405 | xasprintf(&abuf, "%s\r\n", abuf); | ||
| 406 | my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established); | ||
| 407 | if (verbose) { | ||
| 408 | printf(_("sent %s\n"), abuf); | ||
| 409 | } | ||
| 410 | |||
| 411 | if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, | ||
| 412 | ssl_established)) <= 0) { | ||
| 413 | result = STATE_CRITICAL; | ||
| 414 | xasprintf(&error_msg, _("recv() failed after sending authuser, ")); | ||
| 415 | break; | ||
| 416 | } | ||
| 417 | if (verbose) { | ||
| 418 | printf(_("received %s\n"), buffer); | ||
| 419 | } | ||
| 420 | if (strncmp(buffer, "334", 3) != 0) { | ||
| 421 | result = STATE_CRITICAL; | ||
| 422 | xasprintf(&error_msg, _("invalid response received after authuser, ")); | ||
| 423 | break; | ||
| 424 | } | ||
| 425 | /* encode authpass with base64 */ | ||
| 426 | base64_encode_alloc(config.authpass, strlen(config.authpass), &abuf); | ||
| 427 | xasprintf(&abuf, "%s\r\n", abuf); | ||
| 428 | my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established); | ||
| 429 | if (verbose) { | ||
| 430 | printf(_("sent %s\n"), abuf); | ||
| 431 | } | ||
| 432 | if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, | ||
| 433 | ssl_established)) <= 0) { | ||
| 434 | result = STATE_CRITICAL; | ||
| 435 | xasprintf(&error_msg, _("recv() failed after sending authpass, ")); | ||
| 436 | break; | ||
| 437 | } | ||
| 438 | if (verbose) { | ||
| 439 | printf(_("received %s\n"), buffer); | ||
| 440 | } | ||
| 441 | if (strncmp(buffer, "235", 3) != 0) { | ||
| 442 | result = STATE_CRITICAL; | ||
| 443 | xasprintf(&error_msg, _("invalid response received after authpass, ")); | ||
| 444 | break; | ||
| 445 | } | ||
| 446 | break; | 496 | break; |
| 447 | } while (false); | 497 | } |
| 448 | } else { | ||
| 449 | result = STATE_CRITICAL; | ||
| 450 | xasprintf(&error_msg, _("only authtype LOGIN is supported, ")); | ||
| 451 | } | ||
| 452 | } | ||
| 453 | 498 | ||
| 454 | /* tell the server we're done */ | 499 | /* encode authuser with base64 */ |
| 455 | smtp_quit(config, buffer, socket_descriptor, ssl_established); | 500 | base64_encode_alloc(config.authuser, strlen(config.authuser), &abuf); |
| 501 | xasprintf(&abuf, "%s\r\n", abuf); | ||
| 502 | my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established); | ||
| 503 | if (verbose) { | ||
| 504 | printf(_("sent %s\n"), abuf); | ||
| 505 | } | ||
| 506 | |||
| 507 | if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, | ||
| 508 | ssl_established)) <= 0) { | ||
| 509 | xasprintf(&sc_auth.output, "recv() failed after sending authuser"); | ||
| 510 | sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL); | ||
| 511 | break; | ||
| 512 | } | ||
| 513 | |||
| 514 | if (verbose) { | ||
| 515 | printf(_("received %s\n"), buffer); | ||
| 516 | } | ||
| 517 | |||
| 518 | if (strncmp(buffer, "334", 3) != 0) { | ||
| 519 | xasprintf(&sc_auth.output, "invalid response received after authuser"); | ||
| 520 | sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL); | ||
| 521 | break; | ||
| 522 | } | ||
| 456 | 523 | ||
| 457 | /* finally close the connection */ | 524 | /* encode authpass with base64 */ |
| 458 | close(socket_descriptor); | 525 | base64_encode_alloc(config.authpass, strlen(config.authpass), &abuf); |
| 526 | xasprintf(&abuf, "%s\r\n", abuf); | ||
| 527 | my_send(config, abuf, (int)strlen(abuf), socket_descriptor, ssl_established); | ||
| 528 | |||
| 529 | if (verbose) { | ||
| 530 | printf(_("sent %s\n"), abuf); | ||
| 531 | } | ||
| 532 | |||
| 533 | if ((ret = recvlines(config, buffer, MAX_INPUT_BUFFER, socket_descriptor, | ||
| 534 | ssl_established)) <= 0) { | ||
| 535 | xasprintf(&sc_auth.output, "recv() failed after sending authpass"); | ||
| 536 | sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL); | ||
| 537 | break; | ||
| 538 | } | ||
| 539 | |||
| 540 | if (verbose) { | ||
| 541 | printf(_("received %s\n"), buffer); | ||
| 542 | } | ||
| 543 | |||
| 544 | if (strncmp(buffer, "235", 3) != 0) { | ||
| 545 | xasprintf(&sc_auth.output, "invalid response received after authpass"); | ||
| 546 | sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL); | ||
| 547 | break; | ||
| 548 | } | ||
| 549 | break; | ||
| 550 | } while (false); | ||
| 551 | } else { | ||
| 552 | sc_auth = mp_set_subcheck_state(sc_auth, STATE_CRITICAL); | ||
| 553 | xasprintf(&sc_auth.output, "only authtype LOGIN is supported"); | ||
| 554 | } | ||
| 555 | |||
| 556 | mp_add_subcheck_to_check(&overall, sc_auth); | ||
| 459 | } | 557 | } |
| 460 | 558 | ||
| 559 | /* tell the server we're done */ | ||
| 560 | smtp_quit(config, buffer, socket_descriptor, ssl_established); | ||
| 561 | |||
| 562 | /* finally close the connection */ | ||
| 563 | close(socket_descriptor); | ||
| 564 | |||
| 461 | /* reset the alarm */ | 565 | /* reset the alarm */ |
| 462 | alarm(0); | 566 | alarm(0); |
| 463 | 567 | ||
| 464 | long microsec = deltime(start_time); | 568 | long microsec = deltime(start_time); |
| 465 | double elapsed_time = (double)microsec / 1.0e6; | 569 | double elapsed_time = (double)microsec / 1.0e6; |
| 466 | 570 | ||
| 467 | if (result == STATE_OK) { | 571 | mp_perfdata pd_elapsed_time = perfdata_init(); |
| 468 | if (config.check_critical_time && elapsed_time > config.critical_time) { | 572 | pd_elapsed_time = mp_set_pd_value(pd_elapsed_time, elapsed_time); |
| 469 | result = STATE_CRITICAL; | 573 | pd_elapsed_time.label = "time"; |
| 470 | } else if (config.check_warning_time && elapsed_time > config.warning_time) { | 574 | pd_elapsed_time.uom = "s"; |
| 471 | result = STATE_WARNING; | 575 | |
| 472 | } | 576 | pd_elapsed_time = mp_pd_set_thresholds(pd_elapsed_time, config.connection_time); |
| 473 | } | ||
| 474 | 577 | ||
| 475 | printf(_("SMTP %s - %s%.3f sec. response time%s%s|%s\n"), state_text(result), error_msg, | 578 | mp_subcheck sc_connection_time = mp_subcheck_init(); |
| 476 | elapsed_time, verbose ? ", " : "", verbose ? buffer : "", | 579 | xasprintf(&sc_connection_time.output, "connection time: %.3gs", elapsed_time); |
| 477 | fperfdata("time", elapsed_time, "s", config.check_warning_time, config.warning_time, | 580 | sc_connection_time = |
| 478 | config.check_critical_time, config.critical_time, true, 0, false, 0)); | 581 | mp_set_subcheck_state(sc_connection_time, mp_get_pd_status(pd_elapsed_time)); |
| 582 | mp_add_subcheck_to_check(&overall, sc_connection_time); | ||
| 479 | 583 | ||
| 480 | exit(result); | 584 | mp_exit(overall); |
| 481 | } | 585 | } |
| 482 | 586 | ||
| 483 | /* process command-line arguments */ | 587 | /* process command-line arguments */ |
| 484 | check_smtp_config_wrapper process_arguments(int argc, char **argv) { | 588 | check_smtp_config_wrapper process_arguments(int argc, char **argv) { |
| 485 | enum { | 589 | enum { |
| 486 | SNI_OPTION = CHAR_MAX + 1 | 590 | SNI_OPTION = CHAR_MAX + 1, |
| 591 | output_format_index, | ||
| 592 | ignore_certificate_expiration_index, | ||
| 487 | }; | 593 | }; |
| 488 | 594 | ||
| 489 | int option = 0; | 595 | int option = 0; |
| 490 | static struct option longopts[] = {{"hostname", required_argument, 0, 'H'}, | 596 | static struct option longopts[] = { |
| 491 | {"expect", required_argument, 0, 'e'}, | 597 | {"hostname", required_argument, 0, 'H'}, |
| 492 | {"critical", required_argument, 0, 'c'}, | 598 | {"expect", required_argument, 0, 'e'}, |
| 493 | {"warning", required_argument, 0, 'w'}, | 599 | {"critical", required_argument, 0, 'c'}, |
| 494 | {"timeout", required_argument, 0, 't'}, | 600 | {"warning", required_argument, 0, 'w'}, |
| 495 | {"port", required_argument, 0, 'p'}, | 601 | {"timeout", required_argument, 0, 't'}, |
| 496 | {"from", required_argument, 0, 'f'}, | 602 | {"port", required_argument, 0, 'p'}, |
| 497 | {"fqdn", required_argument, 0, 'F'}, | 603 | {"from", required_argument, 0, 'f'}, |
| 498 | {"authtype", required_argument, 0, 'A'}, | 604 | {"fqdn", required_argument, 0, 'F'}, |
| 499 | {"authuser", required_argument, 0, 'U'}, | 605 | {"authtype", required_argument, 0, 'A'}, |
| 500 | {"authpass", required_argument, 0, 'P'}, | 606 | {"authuser", required_argument, 0, 'U'}, |
| 501 | {"command", required_argument, 0, 'C'}, | 607 | {"authpass", required_argument, 0, 'P'}, |
| 502 | {"response", required_argument, 0, 'R'}, | 608 | {"command", required_argument, 0, 'C'}, |
| 503 | {"verbose", no_argument, 0, 'v'}, | 609 | {"response", required_argument, 0, 'R'}, |
| 504 | {"version", no_argument, 0, 'V'}, | 610 | {"verbose", no_argument, 0, 'v'}, |
| 505 | {"use-ipv4", no_argument, 0, '4'}, | 611 | {"version", no_argument, 0, 'V'}, |
| 506 | {"use-ipv6", no_argument, 0, '6'}, | 612 | {"use-ipv4", no_argument, 0, '4'}, |
| 507 | {"help", no_argument, 0, 'h'}, | 613 | {"use-ipv6", no_argument, 0, '6'}, |
| 508 | {"lmtp", no_argument, 0, 'L'}, | 614 | {"help", no_argument, 0, 'h'}, |
| 509 | {"ssl", no_argument, 0, 's'}, | 615 | {"lmtp", no_argument, 0, 'L'}, |
| 510 | {"tls", no_argument, 0, 's'}, | 616 | {"ssl", no_argument, 0, 's'}, |
| 511 | {"starttls", no_argument, 0, 'S'}, | 617 | {"tls", no_argument, 0, 's'}, |
| 512 | {"sni", no_argument, 0, SNI_OPTION}, | 618 | {"starttls", no_argument, 0, 'S'}, |
| 513 | {"certificate", required_argument, 0, 'D'}, | 619 | {"sni", no_argument, 0, SNI_OPTION}, |
| 514 | {"ignore-quit-failure", no_argument, 0, 'q'}, | 620 | {"certificate", required_argument, 0, 'D'}, |
| 515 | {"proxy", no_argument, 0, 'r'}, | 621 | {"ignore-quit-failure", no_argument, 0, 'q'}, |
| 516 | {0, 0, 0, 0}}; | 622 | {"proxy", no_argument, 0, 'r'}, |
| 623 | {"ignore-certificate-expiration", no_argument, 0, ignore_certificate_expiration_index}, | ||
| 624 | {"output-format", required_argument, 0, output_format_index}, | ||
| 625 | {0, 0, 0, 0}}; | ||
| 517 | 626 | ||
| 518 | check_smtp_config_wrapper result = { | 627 | check_smtp_config_wrapper result = { |
| 519 | .config = check_smtp_config_init(), | 628 | .config = check_smtp_config_init(), |
| @@ -535,8 +644,8 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 535 | } | 644 | } |
| 536 | } | 645 | } |
| 537 | 646 | ||
| 538 | int command_size = 0; | 647 | unsigned long command_size = 0; |
| 539 | int response_size = 0; | 648 | unsigned long response_size = 0; |
| 540 | bool implicit_tls = false; | 649 | bool implicit_tls = false; |
| 541 | int server_port_option = 0; | 650 | int server_port_option = 0; |
| 542 | while (true) { | 651 | while (true) { |
| @@ -591,7 +700,7 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 591 | result.config.commands = | 700 | result.config.commands = |
| 592 | realloc(result.config.commands, sizeof(char *) * command_size); | 701 | realloc(result.config.commands, sizeof(char *) * command_size); |
| 593 | if (result.config.commands == NULL) { | 702 | if (result.config.commands == NULL) { |
| 594 | die(STATE_UNKNOWN, _("Could not realloc() units [%d]\n"), | 703 | die(STATE_UNKNOWN, _("Could not realloc() units [%lu]\n"), |
| 595 | result.config.ncommands); | 704 | result.config.ncommands); |
| 596 | } | 705 | } |
| 597 | } | 706 | } |
| @@ -605,7 +714,7 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 605 | result.config.responses = | 714 | result.config.responses = |
| 606 | realloc(result.config.responses, sizeof(char *) * response_size); | 715 | realloc(result.config.responses, sizeof(char *) * response_size); |
| 607 | if (result.config.responses == NULL) { | 716 | if (result.config.responses == NULL) { |
| 608 | die(STATE_UNKNOWN, _("Could not realloc() units [%d]\n"), | 717 | die(STATE_UNKNOWN, _("Could not realloc() units [%lu]\n"), |
| 609 | result.config.nresponses); | 718 | result.config.nresponses); |
| 610 | } | 719 | } |
| 611 | } | 720 | } |
| @@ -613,22 +722,22 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 613 | strncpy(result.config.responses[result.config.nresponses], optarg, 255); | 722 | strncpy(result.config.responses[result.config.nresponses], optarg, 255); |
| 614 | result.config.nresponses++; | 723 | result.config.nresponses++; |
| 615 | break; | 724 | break; |
| 616 | case 'c': /* critical time threshold */ | 725 | case 'c': /* critical time threshold */ { |
| 617 | if (!is_nonnegative(optarg)) { | 726 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 618 | usage4(_("Critical time must be a positive")); | 727 | if (tmp.error != MP_PARSING_SUCCES) { |
| 619 | } else { | 728 | die(STATE_UNKNOWN, "failed to parse critical time threshold"); |
| 620 | result.config.critical_time = strtod(optarg, NULL); | ||
| 621 | result.config.check_critical_time = true; | ||
| 622 | } | 729 | } |
| 623 | break; | 730 | result.config.connection_time = |
| 624 | case 'w': /* warning time threshold */ | 731 | mp_thresholds_set_warn(result.config.connection_time, tmp.range); |
| 625 | if (!is_nonnegative(optarg)) { | 732 | } break; |
| 626 | usage4(_("Warning time must be a positive")); | 733 | case 'w': /* warning time threshold */ { |
| 627 | } else { | 734 | mp_range_parsed tmp = mp_parse_range_string(optarg); |
| 628 | result.config.warning_time = strtod(optarg, NULL); | 735 | if (tmp.error != MP_PARSING_SUCCES) { |
| 629 | result.config.check_warning_time = true; | 736 | die(STATE_UNKNOWN, "failed to parse warning time threshold"); |
| 630 | } | 737 | } |
| 631 | break; | 738 | result.config.connection_time = |
| 739 | mp_thresholds_set_crit(result.config.connection_time, tmp.range); | ||
| 740 | } break; | ||
| 632 | case 'v': /* verbose */ | 741 | case 'v': /* verbose */ |
| 633 | verbose++; | 742 | verbose++; |
| 634 | break; | 743 | break; |
| @@ -665,7 +774,6 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 665 | } | 774 | } |
| 666 | result.config.days_till_exp_warn = atoi(optarg); | 775 | result.config.days_till_exp_warn = atoi(optarg); |
| 667 | } | 776 | } |
| 668 | result.config.check_cert = true; | ||
| 669 | result.config.ignore_send_quit_failure = true; | 777 | result.config.ignore_send_quit_failure = true; |
| 670 | #else | 778 | #else |
| 671 | usage(_("SSL support not available - install OpenSSL and recompile")); | 779 | usage(_("SSL support not available - install OpenSSL and recompile")); |
| @@ -714,6 +822,21 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 714 | exit(STATE_UNKNOWN); | 822 | exit(STATE_UNKNOWN); |
| 715 | case '?': /* help */ | 823 | case '?': /* help */ |
| 716 | usage5(); | 824 | usage5(); |
| 825 | case output_format_index: { | ||
| 826 | parsed_output_format parser = mp_parse_output_format(optarg); | ||
| 827 | if (!parser.parsing_success) { | ||
| 828 | // TODO List all available formats here, maybe add anothoer usage function | ||
| 829 | printf("Invalid output format: %s\n", optarg); | ||
| 830 | exit(STATE_UNKNOWN); | ||
| 831 | } | ||
| 832 | |||
| 833 | result.config.output_format_is_set = true; | ||
| 834 | result.config.output_format = parser.output_format; | ||
| 835 | break; | ||
| 836 | } | ||
| 837 | case ignore_certificate_expiration_index: { | ||
| 838 | result.config.ignore_certificate_expiration = true; | ||
| 839 | } | ||
| 717 | } | 840 | } |
| 718 | } | 841 | } |
| 719 | 842 | ||
| @@ -742,6 +865,19 @@ check_smtp_config_wrapper process_arguments(int argc, char **argv) { | |||
| 742 | result.config.server_port = server_port_option; | 865 | result.config.server_port = server_port_option; |
| 743 | } | 866 | } |
| 744 | 867 | ||
| 868 | if (result.config.authtype) { | ||
| 869 | if (strcmp(result.config.authtype, "LOGIN") == 0) { | ||
| 870 | if (result.config.authuser == NULL) { | ||
| 871 | usage4("no authuser specified"); | ||
| 872 | } | ||
| 873 | if (result.config.authpass == NULL) { | ||
| 874 | usage4("no authpass specified"); | ||
| 875 | } | ||
| 876 | } else { | ||
| 877 | usage4("only authtype LOGIN is supported"); | ||
| 878 | } | ||
| 879 | } | ||
| 880 | |||
| 745 | return result; | 881 | return result; |
| 746 | } | 882 | } |
| 747 | 883 | ||
| @@ -791,7 +927,7 @@ char *smtp_quit(check_smtp_config config, char buffer[MAX_INPUT_BUFFER], int soc | |||
| 791 | int recvline(char *buf, size_t bufsize, check_smtp_config config, int socket_descriptor, | 927 | int recvline(char *buf, size_t bufsize, check_smtp_config config, int socket_descriptor, |
| 792 | bool ssl_established) { | 928 | bool ssl_established) { |
| 793 | int result; | 929 | int result; |
| 794 | int counter; | 930 | size_t counter; |
| 795 | 931 | ||
| 796 | for (counter = result = 0; counter < bufsize - 1; counter++) { | 932 | for (counter = result = 0; counter < bufsize - 1; counter++) { |
| 797 | if ((result = my_recv(config, &buf[counter], 1, socket_descriptor, ssl_established)) != 1) { | 933 | if ((result = my_recv(config, &buf[counter], 1, socket_descriptor, ssl_established)) != 1) { |
| @@ -799,7 +935,7 @@ int recvline(char *buf, size_t bufsize, check_smtp_config config, int socket_des | |||
| 799 | } | 935 | } |
| 800 | if (buf[counter] == '\n') { | 936 | if (buf[counter] == '\n') { |
| 801 | buf[++counter] = '\0'; | 937 | buf[++counter] = '\0'; |
| 802 | return counter; | 938 | return (int)counter; |
| 803 | } | 939 | } |
| 804 | } | 940 | } |
| 805 | return (result == 1 || counter == 0) ? -2 : result; /* -2 if out of space */ | 941 | return (result == 1 || counter == 0) ? -2 : result; /* -2 if out of space */ |
| @@ -902,11 +1038,15 @@ void print_help(void) { | |||
| 902 | printf(" %s\n", _("Send LHLO instead of HELO/EHLO")); | 1038 | printf(" %s\n", _("Send LHLO instead of HELO/EHLO")); |
| 903 | printf(" %s\n", "-q, --ignore-quit-failure"); | 1039 | printf(" %s\n", "-q, --ignore-quit-failure"); |
| 904 | printf(" %s\n", _("Ignore failure when sending QUIT command to server")); | 1040 | printf(" %s\n", _("Ignore failure when sending QUIT command to server")); |
| 1041 | printf(" %s\n", "--ignore-certificate-expiration"); | ||
| 1042 | printf(" %s\n", _("Ignore certificate expiration")); | ||
| 905 | 1043 | ||
| 906 | printf(UT_WARN_CRIT); | 1044 | printf(UT_WARN_CRIT); |
| 907 | 1045 | ||
| 908 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); | 1046 | printf(UT_CONN_TIMEOUT, DEFAULT_SOCKET_TIMEOUT); |
| 909 | 1047 | ||
| 1048 | printf(UT_OUTPUT_FORMAT); | ||
| 1049 | |||
| 910 | printf(UT_VERBOSE); | 1050 | printf(UT_VERBOSE); |
| 911 | 1051 | ||
| 912 | printf("\n"); | 1052 | printf("\n"); |
diff --git a/plugins/check_smtp.d/config.h b/plugins/check_smtp.d/config.h index 0a6511ef..b0d42ed1 100644 --- a/plugins/check_smtp.d/config.h +++ b/plugins/check_smtp.d/config.h | |||
| @@ -1,6 +1,8 @@ | |||
| 1 | #pragma once | 1 | #pragma once |
| 2 | 2 | ||
| 3 | #include "../../config.h" | 3 | #include "../../config.h" |
| 4 | #include "output.h" | ||
| 5 | #include "thresholds.h" | ||
| 4 | #include <stddef.h> | 6 | #include <stddef.h> |
| 5 | #include <string.h> | 7 | #include <string.h> |
| 6 | 8 | ||
| @@ -18,20 +20,18 @@ typedef struct { | |||
| 18 | char *server_expect; | 20 | char *server_expect; |
| 19 | bool ignore_send_quit_failure; | 21 | bool ignore_send_quit_failure; |
| 20 | 22 | ||
| 21 | double warning_time; | 23 | mp_thresholds connection_time; |
| 22 | bool check_warning_time; | 24 | |
| 23 | double critical_time; | ||
| 24 | bool check_critical_time; | ||
| 25 | bool use_ehlo; | 25 | bool use_ehlo; |
| 26 | bool use_lhlo; | 26 | bool use_lhlo; |
| 27 | 27 | ||
| 28 | char *from_arg; | 28 | char *from_arg; |
| 29 | bool send_mail_from; | 29 | bool send_mail_from; |
| 30 | 30 | ||
| 31 | int ncommands; | 31 | unsigned long ncommands; |
| 32 | char **commands; | 32 | char **commands; |
| 33 | 33 | ||
| 34 | int nresponses; | 34 | unsigned long nresponses; |
| 35 | char **responses; | 35 | char **responses; |
| 36 | 36 | ||
| 37 | char *authtype; | 37 | char *authtype; |
| @@ -40,13 +40,17 @@ typedef struct { | |||
| 40 | 40 | ||
| 41 | bool use_proxy_prefix; | 41 | bool use_proxy_prefix; |
| 42 | #ifdef HAVE_SSL | 42 | #ifdef HAVE_SSL |
| 43 | bool check_cert; | ||
| 44 | int days_till_exp_warn; | 43 | int days_till_exp_warn; |
| 45 | int days_till_exp_crit; | 44 | int days_till_exp_crit; |
| 46 | bool use_ssl; | 45 | bool use_ssl; |
| 47 | bool use_starttls; | 46 | bool use_starttls; |
| 48 | bool use_sni; | 47 | bool use_sni; |
| 48 | |||
| 49 | bool ignore_certificate_expiration; | ||
| 49 | #endif | 50 | #endif |
| 51 | |||
| 52 | bool output_format_is_set; | ||
| 53 | mp_output_format output_format; | ||
| 50 | } check_smtp_config; | 54 | } check_smtp_config; |
| 51 | 55 | ||
| 52 | check_smtp_config check_smtp_config_init() { | 56 | check_smtp_config check_smtp_config_init() { |
| @@ -58,10 +62,7 @@ check_smtp_config check_smtp_config_init() { | |||
| 58 | .server_expect = SMTP_EXPECT, | 62 | .server_expect = SMTP_EXPECT, |
| 59 | .ignore_send_quit_failure = false, | 63 | .ignore_send_quit_failure = false, |
| 60 | 64 | ||
| 61 | .warning_time = 0, | 65 | .connection_time = mp_thresholds_init(), |
| 62 | .check_warning_time = false, | ||
| 63 | .critical_time = 0, | ||
| 64 | .check_critical_time = false, | ||
| 65 | .use_ehlo = false, | 66 | .use_ehlo = false, |
| 66 | .use_lhlo = false, | 67 | .use_lhlo = false, |
| 67 | 68 | ||
| @@ -80,13 +81,16 @@ check_smtp_config check_smtp_config_init() { | |||
| 80 | 81 | ||
| 81 | .use_proxy_prefix = false, | 82 | .use_proxy_prefix = false, |
| 82 | #ifdef HAVE_SSL | 83 | #ifdef HAVE_SSL |
| 83 | .check_cert = false, | ||
| 84 | .days_till_exp_warn = 0, | 84 | .days_till_exp_warn = 0, |
| 85 | .days_till_exp_crit = 0, | 85 | .days_till_exp_crit = 0, |
| 86 | .use_ssl = false, | 86 | .use_ssl = false, |
| 87 | .use_starttls = false, | 87 | .use_starttls = false, |
| 88 | .use_sni = false, | 88 | .use_sni = false, |
| 89 | |||
| 90 | .ignore_certificate_expiration = false, | ||
| 89 | #endif | 91 | #endif |
| 92 | |||
| 93 | .output_format_is_set = false, | ||
| 90 | }; | 94 | }; |
| 91 | return tmp; | 95 | return tmp; |
| 92 | } | 96 | } |
diff --git a/plugins/netutils.h b/plugins/netutils.h index c4461113..dbd22398 100644 --- a/plugins/netutils.h +++ b/plugins/netutils.h | |||
| @@ -114,6 +114,26 @@ int np_net_ssl_init_with_hostname_version_and_cert(int socket, char *host_name, | |||
| 114 | void np_net_ssl_cleanup(void); | 114 | void np_net_ssl_cleanup(void); |
| 115 | int np_net_ssl_write(const void *buf, int num); | 115 | int np_net_ssl_write(const void *buf, int num); |
| 116 | int np_net_ssl_read(void *buf, int num); | 116 | int np_net_ssl_read(void *buf, int num); |
| 117 | |||
| 118 | typedef enum { | ||
| 119 | ALL_OK, | ||
| 120 | NO_SERVER_CERTIFICATE_PRESENT, | ||
| 121 | UNABLE_TO_RETRIEVE_CERTIFICATE_SUBJECT, | ||
| 122 | WRONG_TIME_FORMAT_IN_CERTIFICATE, | ||
| 123 | } retrieve_expiration_date_errors; | ||
| 124 | |||
| 125 | typedef struct { | ||
| 126 | double remaining_seconds; | ||
| 127 | retrieve_expiration_date_errors errors; | ||
| 128 | } retrieve_expiration_time_result; | ||
| 129 | |||
| 130 | typedef struct { | ||
| 131 | mp_state_enum result_state; | ||
| 132 | double remaining_seconds; | ||
| 133 | retrieve_expiration_date_errors errors; | ||
| 134 | } net_ssl_check_cert_result; | ||
| 135 | net_ssl_check_cert_result np_net_ssl_check_cert2(int days_till_exp_warn, int days_till_exp_crit); | ||
| 136 | |||
| 117 | mp_state_enum np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit); | 137 | mp_state_enum np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit); |
| 118 | mp_subcheck mp_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit); | 138 | mp_subcheck mp_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit); |
| 119 | #endif /* HAVE_SSL */ | 139 | #endif /* HAVE_SSL */ |
diff --git a/plugins/sslutils.c b/plugins/sslutils.c index 0e6d7525..c58a35ab 100644 --- a/plugins/sslutils.c +++ b/plugins/sslutils.c | |||
| @@ -312,6 +312,138 @@ mp_state_enum np_net_ssl_check_certificate(X509 *certificate, int days_till_exp_ | |||
| 312 | # endif /* USE_OPENSSL */ | 312 | # endif /* USE_OPENSSL */ |
| 313 | } | 313 | } |
| 314 | 314 | ||
| 315 | retrieve_expiration_time_result np_net_ssl_get_cert_expiration(X509 *certificate) { | ||
| 316 | # ifdef USE_OPENSSL | ||
| 317 | retrieve_expiration_time_result result = { | ||
| 318 | .errors = ALL_OK, | ||
| 319 | .remaining_seconds = 0, | ||
| 320 | }; | ||
| 321 | |||
| 322 | if (!certificate) { | ||
| 323 | // printf("%s\n", _("CRITICAL - No server certificate present to inspect.")); | ||
| 324 | result.errors = NO_SERVER_CERTIFICATE_PRESENT; | ||
| 325 | return result; | ||
| 326 | } | ||
| 327 | |||
| 328 | /* Extract CN from certificate subject */ | ||
| 329 | X509_NAME *subj = X509_get_subject_name(certificate); | ||
| 330 | |||
| 331 | if (!subj) { | ||
| 332 | // printf("%s\n", _("CRITICAL - Cannot retrieve certificate subject.")); | ||
| 333 | result.errors = UNABLE_TO_RETRIEVE_CERTIFICATE_SUBJECT; | ||
| 334 | return result; | ||
| 335 | } | ||
| 336 | |||
| 337 | char cn[MAX_CN_LENGTH] = ""; | ||
| 338 | int cnlen = X509_NAME_get_text_by_NID(subj, NID_commonName, cn, sizeof(cn)); | ||
| 339 | if (cnlen == -1) { | ||
| 340 | strcpy(cn, _("Unknown CN")); | ||
| 341 | } | ||
| 342 | |||
| 343 | /* Retrieve timestamp of certificate */ | ||
| 344 | ASN1_STRING *expiration_timestamp = X509_get_notAfter(certificate); | ||
| 345 | |||
| 346 | int offset = 0; | ||
| 347 | struct tm stamp = {}; | ||
| 348 | /* Generate tm structure to process timestamp */ | ||
| 349 | if (expiration_timestamp->type == V_ASN1_UTCTIME) { | ||
| 350 | if (expiration_timestamp->length < 10) { | ||
| 351 | result.errors = WRONG_TIME_FORMAT_IN_CERTIFICATE; | ||
| 352 | return result; | ||
| 353 | } | ||
| 354 | |||
| 355 | stamp.tm_year = | ||
| 356 | (expiration_timestamp->data[0] - '0') * 10 + (expiration_timestamp->data[1] - '0'); | ||
| 357 | if (stamp.tm_year < 50) { | ||
| 358 | stamp.tm_year += 100; | ||
| 359 | } | ||
| 360 | offset = 0; | ||
| 361 | } else { | ||
| 362 | if (expiration_timestamp->length < 12) { | ||
| 363 | result.errors = WRONG_TIME_FORMAT_IN_CERTIFICATE; | ||
| 364 | return result; | ||
| 365 | } | ||
| 366 | |||
| 367 | stamp.tm_year = (expiration_timestamp->data[0] - '0') * 1000 + | ||
| 368 | (expiration_timestamp->data[1] - '0') * 100 + | ||
| 369 | (expiration_timestamp->data[2] - '0') * 10 + | ||
| 370 | (expiration_timestamp->data[3] - '0'); | ||
| 371 | stamp.tm_year -= 1900; | ||
| 372 | offset = 2; | ||
| 373 | } | ||
| 374 | stamp.tm_mon = (expiration_timestamp->data[2 + offset] - '0') * 10 + | ||
| 375 | (expiration_timestamp->data[3 + offset] - '0') - 1; | ||
| 376 | stamp.tm_mday = (expiration_timestamp->data[4 + offset] - '0') * 10 + | ||
| 377 | (expiration_timestamp->data[5 + offset] - '0'); | ||
| 378 | stamp.tm_hour = (expiration_timestamp->data[6 + offset] - '0') * 10 + | ||
| 379 | (expiration_timestamp->data[7 + offset] - '0'); | ||
| 380 | stamp.tm_min = (expiration_timestamp->data[8 + offset] - '0') * 10 + | ||
| 381 | (expiration_timestamp->data[9 + offset] - '0'); | ||
| 382 | stamp.tm_sec = (expiration_timestamp->data[10 + offset] - '0') * 10 + | ||
| 383 | (expiration_timestamp->data[11 + offset] - '0'); | ||
| 384 | stamp.tm_isdst = -1; | ||
| 385 | |||
| 386 | time_t tm_t = timegm(&stamp); | ||
| 387 | double time_left = difftime(tm_t, time(NULL)); | ||
| 388 | result.remaining_seconds = time_left; | ||
| 389 | |||
| 390 | char *timezone = getenv("TZ"); | ||
| 391 | setenv("TZ", "GMT", 1); | ||
| 392 | tzset(); | ||
| 393 | |||
| 394 | char timestamp[50] = ""; | ||
| 395 | strftime(timestamp, 50, "%c %z", localtime(&tm_t)); | ||
| 396 | if (timezone) { | ||
| 397 | setenv("TZ", timezone, 1); | ||
| 398 | } else { | ||
| 399 | unsetenv("TZ"); | ||
| 400 | } | ||
| 401 | |||
| 402 | tzset(); | ||
| 403 | |||
| 404 | X509_free(certificate); | ||
| 405 | |||
| 406 | return result; | ||
| 407 | # else /* ifndef USE_OPENSSL */ | ||
| 408 | printf("%s\n", _("WARNING - Plugin does not support checking certificates.")); | ||
| 409 | return STATE_WARNING; | ||
| 410 | # endif /* USE_OPENSSL */ | ||
| 411 | } | ||
| 412 | |||
| 413 | net_ssl_check_cert_result np_net_ssl_check_cert2(int days_till_exp_warn, int days_till_exp_crit) { | ||
| 414 | # ifdef USE_OPENSSL | ||
| 415 | X509 *certificate = NULL; | ||
| 416 | certificate = SSL_get_peer_certificate(s); | ||
| 417 | |||
| 418 | retrieve_expiration_time_result expiration_date = np_net_ssl_get_cert_expiration(certificate); | ||
| 419 | |||
| 420 | net_ssl_check_cert_result result = { | ||
| 421 | .result_state = STATE_UNKNOWN, | ||
| 422 | .remaining_seconds = expiration_date.remaining_seconds, | ||
| 423 | .errors = expiration_date.errors, | ||
| 424 | }; | ||
| 425 | |||
| 426 | if (expiration_date.errors == ALL_OK) { | ||
| 427 | // got a valid expiration date | ||
| 428 | unsigned int remaining_days = result.remaining_seconds / 86400; | ||
| 429 | |||
| 430 | if (remaining_days < days_till_exp_crit) { | ||
| 431 | result.result_state = STATE_CRITICAL; | ||
| 432 | } else if (remaining_days < days_till_exp_warn) { | ||
| 433 | result.result_state = STATE_WARNING; | ||
| 434 | } else { | ||
| 435 | result.result_state = STATE_OK; | ||
| 436 | } | ||
| 437 | } | ||
| 438 | |||
| 439 | return result; | ||
| 440 | |||
| 441 | # else /* ifndef USE_OPENSSL */ | ||
| 442 | printf("%s\n", _("WARNING - Plugin does not support checking certificates.")); | ||
| 443 | return STATE_WARNING; | ||
| 444 | # endif /* USE_OPENSSL */ | ||
| 445 | } | ||
| 446 | |||
| 315 | mp_state_enum np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit) { | 447 | mp_state_enum np_net_ssl_check_cert(int days_till_exp_warn, int days_till_exp_crit) { |
| 316 | # ifdef USE_OPENSSL | 448 | # ifdef USE_OPENSSL |
| 317 | X509 *certificate = NULL; | 449 | X509 *certificate = NULL; |
diff --git a/plugins/t/check_smtp.t b/plugins/t/check_smtp.t index 73b4a1fd..c2f53c3d 100644 --- a/plugins/t/check_smtp.t +++ b/plugins/t/check_smtp.t | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | # | 5 | # |
| 6 | 6 | ||
| 7 | use strict; | 7 | use strict; |
| 8 | use warnings; | ||
| 8 | use Test::More; | 9 | use Test::More; |
| 9 | use NPTest; | 10 | use NPTest; |
| 10 | 11 | ||
| @@ -24,7 +25,7 @@ my $hostname_invalid = getTestParameter( "NP_HOSTNAME_INVALID", | |||
| 24 | "An invalid (not known to DNS) hostname", "nosuchhost" ); | 25 | "An invalid (not known to DNS) hostname", "nosuchhost" ); |
| 25 | my $res; | 26 | my $res; |
| 26 | 27 | ||
| 27 | plan tests => 15; | 28 | plan tests => 13; |
| 28 | 29 | ||
| 29 | SKIP: { | 30 | SKIP: { |
| 30 | skip "No SMTP server defined", 4 unless $host_tcp_smtp; | 31 | skip "No SMTP server defined", 4 unless $host_tcp_smtp; |
| @@ -42,12 +43,11 @@ SKIP: { | |||
| 42 | 43 | ||
| 43 | TODO: { | 44 | TODO: { |
| 44 | local $TODO = "Output is over two lines"; | 45 | local $TODO = "Output is over two lines"; |
| 45 | like ( $res->output, qr/^SMTP WARNING/, "Correct error message" ); | ||
| 46 | } | 46 | } |
| 47 | 47 | ||
| 48 | $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp --ssl -p 25" ); | 48 | $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp --ssl -p 25" ); |
| 49 | is ($res->return_code, 2, "Check rc of connecting to $host_tcp_smtp with TLS on standard SMTP port" ); | 49 | is ($res->return_code, 2, "Check rc of connecting to $host_tcp_smtp with TLS on standard SMTP port" ); |
| 50 | like ($res->output, qr/^CRITICAL - Cannot make SSL connection\./, "Check output of connecting to $host_tcp_smtp with TLS on standard SMTP port"); | 50 | like ($res->output, qr/cannot create TLS context/, "Check output of connecting to $host_tcp_smtp with TLS on standard SMTP port"); |
| 51 | } | 51 | } |
| 52 | 52 | ||
| 53 | SKIP: { | 53 | SKIP: { |
| @@ -68,7 +68,6 @@ SKIP: { | |||
| 68 | skip "No SMTP server with TLS defined", 1 unless $host_tcp_smtp_tls; | 68 | skip "No SMTP server with TLS defined", 1 unless $host_tcp_smtp_tls; |
| 69 | $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls --ssl" ); | 69 | $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls --ssl" ); |
| 70 | is ($res->return_code, 0, "Check rc of connecting to $host_tcp_smtp_tls with TLS" ); | 70 | is ($res->return_code, 0, "Check rc of connecting to $host_tcp_smtp_tls with TLS" ); |
| 71 | like ($res->output, qr/^SMTP OK - /, "Check output of connecting to $host_tcp_smtp_tls with TLS" ); | ||
| 72 | 71 | ||
| 73 | my $unused_port = 4465; | 72 | my $unused_port = 4465; |
| 74 | $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls -p $unused_port --ssl" ); | 73 | $res = NPTest->testCmd( "./check_smtp -H $host_tcp_smtp_tls -p $unused_port --ssl" ); |
