diff options
author | Andreas Baumann <mail@andreasbaumann.cc> | 2017-04-19 14:36:01 +0200 |
---|---|---|
committer | Andreas Baumann <mail@andreasbaumann.cc> | 2017-04-19 14:36:01 +0200 |
commit | 4355136fdffe94d03f2790b921a59a089ef2bddf (patch) | |
tree | 0f985d691dea081a25241410e9cf8e83d7ec9150 | |
parent | 783268ff84e5ff388ae77df4ea1abe48d8be9c1f (diff) | |
download | monitoring-plugins-4355136.tar.gz |
some work on certificate checking for non-OpenSSL libraries
-rw-r--r-- | plugins/check_curl.c | 88 |
1 files changed, 77 insertions, 11 deletions
diff --git a/plugins/check_curl.c b/plugins/check_curl.c index ff79f15b..5ed47e2c 100644 --- a/plugins/check_curl.c +++ b/plugins/check_curl.c | |||
@@ -149,6 +149,10 @@ int onredirect = STATE_OK; | |||
149 | int use_ssl = FALSE; | 149 | int use_ssl = FALSE; |
150 | int use_sni = TRUE; | 150 | int use_sni = TRUE; |
151 | int check_cert = FALSE; | 151 | int check_cert = FALSE; |
152 | union { | ||
153 | struct curl_slist* to_info; | ||
154 | struct curl_certinfo* to_certinfo; | ||
155 | } cert_ptr; | ||
152 | int ssl_version = CURL_SSLVERSION_DEFAULT; | 156 | int ssl_version = CURL_SSLVERSION_DEFAULT; |
153 | char *client_cert = NULL; | 157 | char *client_cert = NULL; |
154 | char *client_privkey = NULL; | 158 | char *client_privkey = NULL; |
@@ -212,6 +216,10 @@ main (int argc, char **argv) | |||
212 | 216 | ||
213 | int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) | 217 | int verify_callback(int preverify_ok, X509_STORE_CTX *x509_ctx) |
214 | { | 218 | { |
219 | /* TODO: we get all certificates of the chain, so which ones | ||
220 | * should we test? | ||
221 | * TODO: is the last certificate always the server certificate? | ||
222 | */ | ||
215 | cert = X509_STORE_CTX_get_current_cert(x509_ctx); | 223 | cert = X509_STORE_CTX_get_current_cert(x509_ctx); |
216 | return 1; | 224 | return 1; |
217 | } | 225 | } |
@@ -330,6 +338,8 @@ check_http (void) | |||
330 | /* set HTTP headers */ | 338 | /* set HTTP headers */ |
331 | handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPHEADER, header_list ), "CURLOPT_HTTPHEADER"); | 339 | handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_HTTPHEADER, header_list ), "CURLOPT_HTTPHEADER"); |
332 | 340 | ||
341 | #ifdef LIBCURL_FEATURE_SSL | ||
342 | |||
333 | /* set SSL version, warn about unsecure or unsupported versions */ | 343 | /* set SSL version, warn about unsecure or unsupported versions */ |
334 | if (use_ssl) { | 344 | if (use_ssl) { |
335 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION"); | 345 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSLVERSION, ssl_version), "CURLOPT_SSLVERSION"); |
@@ -344,7 +354,7 @@ check_http (void) | |||
344 | /* per default if we have a CA verify both the peer and the | 354 | /* per default if we have a CA verify both the peer and the |
345 | * hostname in the certificate, can be switched off later */ | 355 | * hostname in the certificate, can be switched off later */ |
346 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CAINFO, ca_cert), "CURLOPT_CAINFO"); | 356 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_CAINFO, ca_cert), "CURLOPT_CAINFO"); |
347 | handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 2), "CURLOPT_SSL_VERIFYPEER"); | 357 | handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYPEER, 1), "CURLOPT_SSL_VERIFYPEER"); |
348 | handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 2), "CURLOPT_SSL_VERIFYHOST"); | 358 | handle_curl_option_return_code (curl_easy_setopt( curl, CURLOPT_SSL_VERIFYHOST, 2), "CURLOPT_SSL_VERIFYHOST"); |
349 | } else { | 359 | } else { |
350 | /* backward-compatible behaviour, be tolerant in checks | 360 | /* backward-compatible behaviour, be tolerant in checks |
@@ -354,11 +364,28 @@ check_http (void) | |||
354 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0), "CURLOPT_SSL_VERIFYPEER"); | 364 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYPEER, 0), "CURLOPT_SSL_VERIFYPEER"); |
355 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0), "CURLOPT_SSL_VERIFYHOST"); | 365 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_SSL_VERIFYHOST, 0), "CURLOPT_SSL_VERIFYHOST"); |
356 | } | 366 | } |
357 | 367 | ||
358 | /* set callback to extract certificate */ | 368 | /* try hard to get a stack of certificates to verify against */ |
359 | if(check_cert) { | 369 | if (check_cert) |
370 | #if LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) | ||
371 | /* inform curl to report back certificates (this works for OpenSSL, NSS at least) */ | ||
372 | curl_easy_setopt (curl, CURLOPT_CERTINFO, 1L); | ||
373 | #ifdef USE_OPENSSL | ||
374 | /* set callback to extract certificate with OpenSSL context function (works with | ||
375 | * OpenSSL only!) | ||
376 | */ | ||
360 | handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION"); | 377 | handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION"); |
361 | } | 378 | #endif /* USE_OPENSSL */ |
379 | #else /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */ | ||
380 | #ifdef USE_OPENSSL | ||
381 | /* Too old curl library, hope we have OpenSSL */ | ||
382 | handle_curl_option_return_code (curl_easy_setopt(curl, CURLOPT_SSL_CTX_FUNCTION, sslctxfun), "CURLOPT_SSL_CTX_FUNCTION"); | ||
383 | #else | ||
384 | die (STATE_CRITICAL, "HTTP CRITICAL - Cannot retrieve certificates (no CURLOPT_SSL_CTX_FUNCTION, no OpenSSL library)\n"); | ||
385 | #endif /* USE_OPENSSL */ | ||
386 | #endif /* LIBCURL_VERSION_NUM >= MAKE_LIBCURL_VERSION(7, 19, 1) */ | ||
387 | |||
388 | #endif /* HAVE_SSL */ | ||
362 | 389 | ||
363 | /* set default or user-given user agent identification */ | 390 | /* set default or user-given user agent identification */ |
364 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_USERAGENT, user_agent), "CURLOPT_USERAGENT"); | 391 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_USERAGENT, user_agent), "CURLOPT_USERAGENT"); |
@@ -402,8 +429,10 @@ check_http (void) | |||
402 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)"); | 429 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_WHATEVER), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_WHATEVER)"); |
403 | else if (address_family == AF_INET) | 430 | else if (address_family == AF_INET) |
404 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)"); | 431 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V4)"); |
432 | #ifdef USE_IPV6 | ||
405 | else if (address_family == AF_INET6) | 433 | else if (address_family == AF_INET6) |
406 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)"); | 434 | handle_curl_option_return_code (curl_easy_setopt (curl, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V6), "CURLOPT_IPRESOLVE(CURL_IPRESOLVE_V6)"); |
435 | #endif | ||
407 | 436 | ||
408 | /* either send http POST data (any data, not only POST)*/ | 437 | /* either send http POST data (any data, not only POST)*/ |
409 | if (!strcmp(http_method, "POST") ||!strcmp(http_method, "PUT")) { | 438 | if (!strcmp(http_method, "POST") ||!strcmp(http_method, "PUT")) { |
@@ -444,14 +473,41 @@ check_http (void) | |||
444 | } | 473 | } |
445 | 474 | ||
446 | /* certificate checks */ | 475 | /* certificate checks */ |
447 | #ifdef HAVE_SSL | 476 | #ifdef LIBCURL_FEATURE_SSL |
448 | if (use_ssl == TRUE) { | 477 | if (use_ssl == TRUE) { |
449 | if (check_cert == TRUE) { | 478 | if (check_cert == TRUE) { |
479 | if (verbose >= 2) | ||
480 | printf ("**** REQUEST CERTIFICATES ****\n"); | ||
481 | cert_ptr.to_info = NULL; | ||
482 | res = curl_easy_getinfo (curl, CURLINFO_CERTINFO, &cert_ptr.to_info); | ||
483 | if (!res && cert_ptr.to_info) { | ||
484 | int i; | ||
485 | for (i = 0; i < cert_ptr.to_certinfo->num_of_certs; i++) { | ||
486 | struct curl_slist *slist; | ||
487 | for (slist = cert_ptr.to_certinfo->certinfo[i]; slist; slist = slist->next) { | ||
488 | if (verbose >= 2) | ||
489 | printf ("%d ** %s\n", i, slist->data); | ||
490 | } | ||
491 | } | ||
492 | } else { | ||
493 | snprintf (msg, DEFAULT_BUFFER_SIZE, _("Cannot retrieve certificates - cURL returned %d - %s"), | ||
494 | res, curl_easy_strerror(res)); | ||
495 | die (STATE_CRITICAL, "HTTP CRITICAL - %s\n", msg); | ||
496 | } | ||
497 | if (verbose >= 2) | ||
498 | printf ("**** REQUEST CERTIFICATES ****\n"); | ||
499 | /* check certificate with OpenSSL functions, curl has been built against OpenSSL | ||
500 | * and we actually have OpenSSL in the monitoring tools | ||
501 | */ | ||
502 | #ifdef HAVE_SSL | ||
503 | #ifdef USE_OPENSSL | ||
450 | result = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit); | 504 | result = np_net_ssl_check_certificate(cert, days_till_exp_warn, days_till_exp_crit); |
451 | return(result); | 505 | #endif /* USE_OPENSSL */ |
506 | #endif /* HAVE_SSL */ | ||
507 | return result; | ||
452 | } | 508 | } |
453 | } | 509 | } |
454 | #endif /* HAVE_SSL */ | 510 | #endif /* LIBCURL_FEATURE_SSL */ |
455 | 511 | ||
456 | /* we got the data and we executed the request in a given time, so we can append | 512 | /* we got the data and we executed the request in a given time, so we can append |
457 | * performance data to the answer always | 513 | * performance data to the answer always |
@@ -481,7 +537,6 @@ check_http (void) | |||
481 | (int)body_buf.buflen); | 537 | (int)body_buf.buflen); |
482 | } | 538 | } |
483 | 539 | ||
484 | |||
485 | /* return a CRITICAL status if we couldn't read any data */ | 540 | /* return a CRITICAL status if we couldn't read any data */ |
486 | if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0) | 541 | if (strlen(header_buf.buf) == 0 && strlen(body_buf.buf) == 0) |
487 | die (STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n")); | 542 | die (STATE_CRITICAL, _("HTTP CRITICAL - No header received from host\n")); |
@@ -605,6 +660,16 @@ check_http (void) | |||
605 | /* make sure the page is of an appropriate size | 660 | /* make sure the page is of an appropriate size |
606 | * TODO: as far I can tell check_http gets the full size of header and | 661 | * TODO: as far I can tell check_http gets the full size of header and |
607 | * if -N is not given header+body. Does this make sense? | 662 | * if -N is not given header+body. Does this make sense? |
663 | * | ||
664 | * TODO: check_http.c had a get_length function, the question is really | ||
665 | * here what to use? the raw data size of the header_buf, the value of | ||
666 | * Content-Length, both and warn if they differ? Should the length be | ||
667 | * header+body or only body? | ||
668 | * | ||
669 | * One possible policy: | ||
670 | * - use header_buf.buflen (warning, if it mismatches to the Content-Length value | ||
671 | * - if -N (nobody) is given, use Content-Length only and hope the server set | ||
672 | * the value correcly | ||
608 | */ | 673 | */ |
609 | page_len = header_buf.buflen + body_buf.buflen; | 674 | page_len = header_buf.buflen + body_buf.buflen; |
610 | if ((max_page_len > 0) && (page_len > max_page_len)) { | 675 | if ((max_page_len > 0) && (page_len > max_page_len)) { |
@@ -637,8 +702,8 @@ check_http (void) | |||
637 | curlhelp_free_statusline(&status_line); | 702 | curlhelp_free_statusline(&status_line); |
638 | curl_easy_cleanup (curl); | 703 | curl_easy_cleanup (curl); |
639 | curl_global_cleanup (); | 704 | curl_global_cleanup (); |
640 | curlhelp_freewritebuffer(&body_buf); | 705 | curlhelp_freewritebuffer (&body_buf); |
641 | curlhelp_freewritebuffer(&header_buf); | 706 | curlhelp_freewritebuffer (&header_buf); |
642 | if (!strcmp (http_method, "PUT")) { | 707 | if (!strcmp (http_method, "PUT")) { |
643 | curlhelp_freereadbuffer (&put_buf); | 708 | curlhelp_freereadbuffer (&put_buf); |
644 | } | 709 | } |
@@ -1493,6 +1558,7 @@ get_header_value (const struct phr_header* headers, const size_t nof_headers, co | |||
1493 | return NULL; | 1558 | return NULL; |
1494 | } | 1559 | } |
1495 | 1560 | ||
1561 | /* TODO: use CURL_EXTERN time_t curl_getdate(const char *p, const time_t *unused); here */ | ||
1496 | static time_t | 1562 | static time_t |
1497 | parse_time_string (const char *string) | 1563 | parse_time_string (const char *string) |
1498 | { | 1564 | { |